Summary

Guided chironomy can be a way for non-natives to practice. Such intervention should focus on phrases where they have trouble. Design of interface should consider other ways of controlling timing. Followup studies should work with less advanced learners.

Comparison of F0 curve only, no timing

Overall

As a first sanity check, let’s use the same comparison methods as d’Alessandro 2011. They took the correlation and the RMSE of vocal and chironomic imitations with the reference f0 curve.

  • Median for vocal imitation: >0.9 correlation, <1.5ST RMSE
  • Median for chironomic imitation: >0.8 correlation, <2.5ST RMSE

For our data:

all_data %>% filter(condition=="imitation") %>% pull(corr_notiming) %>% median() %>% 
  round(3) %>% paste0(": Median correlation of vocal imitation")
[1] "0.957: Median correlation of vocal imitation"
all_data %>% filter(condition=="guide") %>% pull(corr_notiming) %>% median() %>%
  round(3) %>% paste0(": Median correlation of guided chironomic imitation")
[1] "0.903: Median correlation of guided chironomic imitation"
all_data %>% filter(condition=="blind") %>% pull(corr_notiming) %>% median() %>% 
  round(3) %>% paste0(": Median correlation of blind chironomic imitation")
[1] "0.596: Median correlation of blind chironomic imitation"
all_data %>% filter(condition=="imitation") %>% pull(rmse_notiming) %>% median() %>% 
  round(3) %>% paste0(": Median RMSE of vocal imitation")
[1] "1.197: Median RMSE of vocal imitation"
all_data %>% filter(condition=="guide") %>% pull(rmse_notiming) %>% median() %>%
  round(3) %>% paste0(": Median RMSE of guided chironomic imitation")
[1] "1.911: Median RMSE of guided chironomic imitation"
all_data %>% filter(condition=="blind") %>% pull(rmse_notiming) %>% median() %>% 
  round(3) %>% paste0(": Median RMSE of blind chironomic imitation")
[1] "3.112: Median RMSE of blind chironomic imitation"

In d’Alessandro 2011, the chironomic imitation was non-guided. The worse performance for non-guided imitation for our study may be explained by the added difficulty of finding the intonation curve and the correct timing control.

Slightly better scores arise for chironomic imitation when we use the stylized f0 curve as a reference. Stylization curve simplifies the f0 curve into straight line segments based on a perceptual model. The stylization removes microprosodic details present in natural vocal pronunciations that are not perceptually salient. Resynthesized utterances with f0 replaced by the stylized version are perceptually identical to the original.

Below are aggregate results for all data using the two types of references:

# Correlation
overall_psg_notiming <- all_data %>% ggplot(aes(x=condition, y=corr_psg_notiming)) + 
             geom_boxplot(aes(fill=condition), show.legend = FALSE) +
             scale_fill_manual(values=wes_palette("Moonrise3")) +
             scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
             labs(title="Correlation, No Timing", subtitle="Stylized reference",
              x="Condition", y="Correlation") 

overall_notiming <- all_data %>% ggplot(aes(x=condition, y=corr_notiming)) + 
             geom_boxplot(aes(fill=condition), show.legend = FALSE) +
             scale_fill_manual(values=wes_palette("Moonrise3")) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
             labs(title="", subtitle="Original reference",
              x="Condition", y="Correlation") 

# RMSE
overall_psg_rmse_notiming <- all_data %>% ggplot(aes(x=condition, y=rmse_psg_notiming)) + 
             geom_boxplot(aes(fill=condition), show.legend = FALSE) +
             scale_fill_manual(values=wes_palette("Moonrise2")) +
             scale_y_continuous(breaks=seq(0, 8, by=1)) + 
             labs(title="RMSE Scores, No Timing", subtitle="Stylized reference",
              x="Condition", y="Correlation") 

overall_rmse_notiming <- all_data %>% ggplot(aes(x=condition, y=rmse_notiming)) + 
             geom_boxplot(aes(fill=condition), show.legend = FALSE) +
             scale_fill_manual(values=wes_palette("Moonrise2")) +
             scale_y_continuous(breaks=seq(0, 8, by=1)) + 
             labs(title="", subtitle="Original reference",
              x="Condition", y="Correlation") 

grid.arrange(overall_psg_notiming, overall_notiming, overall_psg_rmse_notiming, overall_rmse_notiming, ncol=2)

all_data %>% filter(condition=="imitation") %>% pull(corr_notiming) %>% median() %>% 
  round(3) %>% paste0(": Median correlation of vocal imitation")
[1] "0.957: Median correlation of vocal imitation"
all_data %>% filter(condition=="guide") %>% pull(corr_psg_notiming) %>% median() %>%
  round(3) %>% paste0(": Median correlation of Chironomic imitation")
[1] "0.944: Median correlation of Chironomic imitation"
all_data %>% filter(condition=="imitation") %>% pull(rmse_notiming) %>% median() %>% 
  round(3) %>% paste0(": Median RMSE of vocal imitation")
[1] "1.197: Median RMSE of vocal imitation"
all_data %>% filter(condition=="guide") %>% pull(rmse_psg_notiming) %>% median() %>%
  round(3) %>% paste0(": Median RMSE of Chironomic imitation")
[1] "1.61: Median RMSE of Chironomic imitation"

For the rest of the comparison, we will be using the stylized version as a reference for the chironomic imitations and the original f0 curve for the vocal pronunciations. Chironomic pronunciations are always a stylization because it is both difficult and unncessary for the hands to produce the same micro-prosodic artifacts as the voice.

notiming_gest_data <- all_data %>% filter(type=='gesture') %>% 
                 mutate(corr_notiming = corr_psg_notiming, rmse_notiming=rmse_psg_notiming) 
notiming_voice_data <- all_data %>%filter(type=="voice")          
notiming_data <-bind_rows(notiming_gest_data, notiming_voice_data)

Native vs Non-natives

Differences are slight between the learner and native groups in this study. This particular group of learners have all taken a class on French intonation and have encountered the phrases used in the study. Their performance for chironomic imitation is even slightly better than that of natives (probably not significant).

Natives have slightly better vocal scores. Their reading is also more similar to the originals when timing is not taken into account.

learners_box <- notiming_data %>% filter(subject %in% learners$id) %>%
  ggplot(aes(x=condition, y=corr_notiming)) + geom_boxplot(aes(fill=condition), show.legend = FALSE) +
  scale_fill_manual(values = wes_palette("GrandBudapest2")) +
  scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
  labs(title="Correlation Scores (original ref)", subtitle="Learners") 
                    
natives_box <- notiming_data %>% filter(subject %in% natives$id) %>%
  ggplot(aes(x=condition, y=corr_notiming)) + geom_boxplot(aes(fill=condition), show.legend = FALSE) +
  scale_fill_manual(values = wes_palette("GrandBudapest2")) +
  scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
  labs(title="", subtitle="Natives")                    

learners_box_rmse <- notiming_data %>% filter(subject %in% learners$id) %>%
  ggplot(aes(x=condition, y=rmse_notiming)) + geom_boxplot(aes(fill=condition), show.legend = FALSE) +
  scale_fill_manual(values = wes_palette("GrandBudapest1")) +
  scale_y_continuous(breaks=seq(0, 8, by=1)) + 
  labs(title="RMSE Scores (original ref)", subtitle="Learners") 
                    
natives_box_rmse <- notiming_data %>% filter(subject %in% natives$id) %>%
  ggplot(aes(x=condition, y=rmse_notiming)) + geom_boxplot(aes(fill=condition), show.legend = FALSE) +
  scale_fill_manual(values = wes_palette("GrandBudapest1")) +
  scale_y_continuous(breaks=seq(0, 8, by=1)) + 
  labs(title="", subtitle="Natives")                    

grid.arrange(learners_box, natives_box, learners_box_rmse, natives_box_rmse, ncol=2) 

Musicians vs Non-musicians

7 of the 10 subjects in d’Alessandro 2011 had a musical practice. It may have helped their performance in the chironomic condition. In our study, 4 of the 10 subjects play music or sing. Musicians had slightly better scores for the blind chironomic condition. Their results are not different from non-musicians in the other conditions.

notiming_data %>% filter(subject %in% musicians$id & condition=="blind") %>% pull(corr_psg_notiming) %>% median() %>% 
  round(3) %>% paste0(": Median correlation of blind chironomy - Musicians")
[1] "0.751: Median correlation of blind chironomy - Musicians"
notiming_data %>% filter(subject %in% nonmus$id & condition=="blind") %>% pull(corr_psg_notiming) %>% median() %>% 
  round(3) %>% paste0(": Median correlation of blind chironomy - Non-musicians")
[1] "0.558: Median correlation of blind chironomy - Non-musicians"
notiming_data %>% filter(subject %in% musicians$id & condition=="blind") %>% pull(rmse_psg_notiming) %>% median() %>% 
  round(3) %>% paste0(": Median correlation of blind chironomy - Musicians")
[1] "2.421: Median correlation of blind chironomy - Musicians"
notiming_data %>% filter(subject %in% nonmus$id & condition=="blind") %>% pull(rmse_psg_notiming) %>% median() %>% 
  round(3) %>% paste0(": Median correlation of blind chironomy - Non-musicians")
[1] "3.015: Median correlation of blind chironomy - Non-musicians"
    
musicians_box <- notiming_data %>% filter(subject %in% musicians$id) %>%
  ggplot(aes(x=condition, y=corr_notiming)) + geom_boxplot(aes(fill=condition), show.legend = FALSE) +
  scale_fill_manual(values = wes_palette("Chevalier1")) +
  scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
  labs(title="Correlation Scores", subtitle="Musicians")
                    
nonmus_box <- notiming_data %>% filter(subject %in% nonmus$id) %>%
  ggplot(aes(x=condition, y=corr_notiming)) + geom_boxplot(aes(fill=condition), show.legend = FALSE) +
  scale_fill_manual(values = wes_palette("Chevalier1")) +
  scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
  labs(title="", subtitle="Non-musicians")                    
 
musicians_box_rmse <- notiming_data %>% filter(subject %in% musicians$id) %>%
  ggplot(aes(x=condition, y=rmse_notiming)) + geom_boxplot(aes(fill=condition), show.legend = FALSE) +
  scale_fill_manual(values = wes_palette("Royal2")) +
  scale_y_continuous(breaks=seq(0, 8, by=1)) + 
  labs(title="RMSE Scores", subtitle="Musicians")
                    
nonmus_box_rmse <- notiming_data %>% filter(subject %in% nonmus$id) %>%
  ggplot(aes(x=condition, y=rmse_notiming)) + geom_boxplot(aes(fill=condition), show.legend = FALSE) +
  scale_fill_manual(values = wes_palette("Royal2")) +
  scale_y_continuous(breaks=seq(0, 8, by=1)) + 
  labs(title="", subtitle="Non-musicians")     

grid.arrange(musicians_box, nonmus_box, musicians_box_rmse, nonmus_box_rmse, ncol=2)

By Phrase

For most phrases, guided chironomy and vocal imitation had comparable scores when timing is not taken into account. Both had higher than >0.9 median correlation for most phrases, and between 0.5 & 2.5ST median RMSE.

For half of the phrases (e.g. 2bis, 7, 8, 10, 11bis, 21bis), guided chironomy had higher median scores for correlation. Some of these phrases (10, 21bis), guided chironomy also had a better (lower) RMSE score.

Blind chironomy varied widely across phrases the phrases. Some phrases were notably more difficult even in the guided chironomy condition.

notiming_data %>%
  mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
  ggplot(aes(x=pid, y=corr_notiming, fill=condition)) +
  scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
  geom_boxplot(width=0.7) + 
  scale_fill_manual(values = wes_palette("Moonrise3")) +
  labs(title="Correlation Scores - all subjects", 
            subtitle="Grouped by phrase",
            x="Phrase id", y="Correlation") #+ theme(aspect.ratio=0.4)

notiming_data %>%
  mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
  ggplot(aes(x=pid, y=rmse_notiming, fill=condition)) +
  geom_boxplot(width=0.7) + 
  scale_fill_manual(values = wes_palette("Moonrise1")) +
  scale_y_continuous(breaks=seq(0, 8, by=1)) + 
  labs(title="RMSE Scores - all subject", 
            subtitle="Grouped by phrase",
            x="Phrase id", y="RMSE") #+ theme(aspect.ratio=0.4)

Phrase and Subject Groups

Native/Non-native

Natives and learners performed quite differently across the different phrases.

  • For learners, reading (lecture) differed from the model the most for phrases 10, 10bis, 21.
  • For non-natives, the only phrase that had median correlation <0.8 in the reading condition was 10bis
  • For some phrases, blind chironomy had pretty good scores (correlation >0.8). These phrases were not all the same for n ative vs non-natives.
  • For some phrases, in the blind chironomy condition, natives had lower scores than non-natives

In discussions after the study, a couple of native speakers reported not agreeing with the reference intonation curve provided for the guided chironomy condition.

c_l <- notiming_data %>% filter(subject %in% learners$id) %>%
  mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
  ggplot(aes(x=pid, y=corr_notiming, fill=condition)) +
  geom_boxplot(width=0.7) + 
  scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
  scale_fill_manual(values = wes_palette("Moonrise3")) +
  labs(title="Correlation Scores, no timing - Learners", 
            subtitle="Grouped by phrase",
            x="Phrase id", y="Correlation") #+ theme(aspect.ratio=0.4)

c_n <- notiming_data %>% filter(subject %in% natives$id) %>%
  mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
  ggplot(aes(x=pid, y=corr_notiming, fill=condition)) +
  geom_boxplot(width=0.7) + 
  scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
  scale_fill_manual(values = wes_palette("Moonrise3")) +
  labs(title="Correlation Scores, no timing - Natives", 
            subtitle="Grouped by phrase",
            x="Phrase id", y="Correlation") #+ theme(aspect.ratio=0.4)

grid.arrange(c_l, c_n, ncol=1)

r_l <- notiming_data %>% filter(subject %in% learners$id) %>%
  mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
  ggplot(aes(x=pid, y=rmse_notiming, fill=condition)) +
  geom_boxplot(width=0.7) + 
  scale_y_continuous(breaks=seq(0, 8, by=1)) + 
  scale_fill_manual(values = wes_palette("Royal2")) +
  labs(title="RMSE Scores - Learners", 
            subtitle="Grouped by phrase",
            x="Phrase id", y="RMSE") 

r_n <- notiming_data %>% filter(subject %in% natives$id) %>%
  mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
  ggplot(aes(x=pid, y=rmse_notiming, fill=condition)) +
  geom_boxplot(width=0.7) + 
  scale_y_continuous(breaks=seq(0, 8, by=1)) + 
  scale_fill_manual(values = wes_palette("Royal2")) +
  labs(title="RMSE Scores - Natives", 
            subtitle="Grouped by phrase",
            x="Phrase id", y="RMSE") 

grid.arrange(r_l, r_n, ncol=1)

Musician/Non-musician

In terms of correlation, musicians did much better than non-musicians in blind chironomy for a few specific phrases (e.g. 2, 7, 8). Some phrases were difficult for everyone (10bis, 21), but musicians still did better.

c_m <- notiming_data %>% filter(subject %in% musicians$id) %>%
  mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
  ggplot(aes(x=pid, y=corr_notiming, fill=condition)) +
  geom_boxplot(width=0.7) + 
  scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
  scale_fill_manual(values = wes_palette("Moonrise3")) +
  labs(title="Correlation Scores, no timing - Musicians", 
            subtitle="Grouped by phrase",
            x="Phrase id", y="Correlation") #+ theme(aspect.ratio=0.4)

c_nm <- notiming_data %>% filter(subject %in% nonmus $id) %>%
  mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
  ggplot(aes(x=pid, y=corr_notiming, fill=condition)) +
  geom_boxplot(width=0.7) + 
  scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
  scale_fill_manual(values = wes_palette("Moonrise3")) +
  labs(title="Correlation Scores, no timing - Non-musicians", 
            subtitle="Grouped by phrase",
            x="Phrase id", y="Correlation") #+ theme(aspect.ratio=0.4)

grid.arrange(c_m, c_nm, ncol=1)

r_m <- notiming_data %>% filter(subject %in% musicians$id) %>%
  mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
  ggplot(aes(x=pid, y=rmse_notiming, fill=condition)) +
  geom_boxplot(width=0.7) + 
  scale_y_continuous(breaks=seq(0, 8, by=1)) + 
  scale_fill_manual(values = wes_palette("Royal2")) +
  labs(title="RMSE Scores - Musicians", 
            subtitle="Grouped by phrase",
            x="Phrase id", y="RMSE") 

r_nm <- notiming_data %>% filter(subject %in% nonmus$id) %>%
  mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
  ggplot(aes(x=pid, y=rmse_notiming, fill=condition)) +
  geom_boxplot(width=0.7) + 
  scale_y_continuous(breaks=seq(0, 8, by=1)) + 
  scale_fill_manual(values = wes_palette("Royal2")) +
  labs(title="RMSE Scores - Nonmus", 
            subtitle="Grouped by phrase",
            x="Phrase id", y="RMSE") 

grid.arrange(r_m, r_nm, ncol=1)

Taking Timing into account

For gestural comparisons, we need to make sure that we are comparing with the right part of the original signal. The part of the reference signal to be compared is taken from the beginning and ending scrub values of the gesture. The timing of the gesture is scaled linearly to match the timing of the reference.

For vocal comparisons, the part of the recording containing the utterance is labeled for both the reference and subject recordings. The timing of the vocal recording is scaled linearly to match the reference. No time warping was done in order to preserve the original rhythm of the recording.

# For gesture data, only keep the prosogram comparisons but call them the same thing as the corresponding comparisons for voice
gest_data2 <- all_data %>% filter(type=='gesture') %>% mutate(corr_notiming = corr_psg_notiming, 
                                                              rmse_notiming = rmse_psg_notiming,
                                                              corr = corr_psg, rmse= rmse_psg) 
long_data <- all_data %>% filter(type== 'voice') %>% bind_rows(gest_data2) %>% 
             # Get rid of columns containing the prosogram comparisons
             mutate(corr_psg = NULL, rmse_psg = NULL, corr_psg_notiming = NULL, rmse_psg_notiming = NULL) %>%
             # Make long version of data
             pivot_longer(c('corr', 'corr_notiming', 'rmse', 'rmse_notiming'), names_to = "metrics", values_to = "score")

Overall

Interesting, the blind chironomy median scores don’t change much because they are already not so great. The scores for the other conditions are worse. Interestingly, guided chironomy performs the best when timing is taken into account. Even though its scores are slightly worse than when timing is not taken into account, it still manages to have “good” scores (in comparison with results from d’Alessandro 2011) – a median correlation of >0.8 and median RMSE around 2ST.

For reading, it is normal that there would be more variation in timing.

long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              ggplot(aes(x=condition, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=0.2)) +
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing")

long_data %>% filter(metrics== 'rmse_notiming' | metrics == 'rmse') %>%
              ggplot(aes(x=condition, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(0, 8, by=1)) + 
              scale_fill_manual(name = "Comparison type", 
                                labels = c("With timing", "No timing"), 
                                values=wes_palette("Moonrise2")) +
              labs(title="RMSE, timing vs no-timing")

Learners vs Natives

Not so much difference between natives and non-natives when timing is taken into account.

l <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% learners$id) %>%
              ggplot(aes(x=condition, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Learners")

n <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% natives$id) %>%
              ggplot(aes(x=condition, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(subtitle="Natives")

grid.arrange(l, n, ncol=1)

l <- long_data %>% filter(metrics== 'rmse_notiming' | metrics == 'rmse') %>%
              filter(subject %in% learners$id) %>%
              ggplot(aes(x=condition, y=score)) +
              scale_y_continuous(breaks=seq(0, 8, by=1)) + 
              geom_boxplot(aes(fill = metrics)) +
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise2")) +
              labs(title="RMSE, timing vs no-timing", subtitle="Learners")

n <- long_data %>% filter(metrics== 'rmse_notiming' | metrics == 'rmse') %>%
              filter(subject %in% natives$id) %>%
              ggplot(aes(x=condition, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(0, 8, by=1)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise2")) +
              labs(subtitle="Natives")

grid.arrange(l, n, ncol=1)

Musicians vs Non-musicians

Not big difference between musicians and non-musicians either when timing is taken into account.

m <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% musicians$id) %>%
              ggplot(aes(x=condition, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Musicians")

nm <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% nonmus$id) %>%
              ggplot(aes(x=condition, y=score)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              geom_boxplot(aes(fill = metrics)) +
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(subtitle="Non-musicians")

grid.arrange(m, nm, ncol=1)

m <- long_data %>% filter(metrics== 'rmse_notiming' | metrics == 'rmse') %>%
              filter(subject %in% musicians$id) %>%
              ggplot(aes(x=condition, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(0, 8, by=1)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise2")) +
              labs(title="RMSE, timing vs no-timing", subtitle="Learners")

nm <- long_data %>% filter(metrics== 'rmse_notiming' | metrics == 'rmse') %>%
              filter(subject %in% nonmus$id) %>%
              ggplot(aes(x=condition, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(0, 8, by=1)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise2")) +
              labs(subtitle="Natives")

grid.arrange(m, nm, ncol=1)

By Phrase

By compariing the difference between guided chironomy with and without timing taken into account, we can see that some phrases were trickier to control the timing of than others (e.g. 7bis, 10, 21, 21bis)

I’m not sure how meaningful it is to compare the vocal pronunciations with without dynamic time warping because there is natural variation in the voice.

ci <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(condition=='guide') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Guided Chironomy")

vi <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(condition=='imitation') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Vocal Comparison")

grid.arrange(ci, vi, ncol=1)

ci <- long_data %>% filter(metrics== 'rmse_notiming' | metrics == 'rmse') %>%
              filter(condition=='guide') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(0, 8, by=1)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Royal2")) +
              labs(title="RMSE, timing vs no-timing", subtitle="Guided Chironomy")

vi <- long_data %>% filter(metrics== 'rmse_notiming' | metrics == 'rmse') %>%
              filter(condition=='imitation') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(0, 8, by=1)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Royal2")) +
              labs(title="RMSE, timing vs no-timing", subtitle="Vocal Comparison")

grid.arrange(ci, vi, ncol=1)

By Phrase and subject groups

For guided chironomy

Seems to be an equalizer between natives and non-natives. Not huge amount of difference.

l <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% learners$id) %>%
              filter(condition=='guide') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Guided Chironomy, Learners")

n <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% natives$id) %>%
              filter(condition=='guide') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Guided Chironomy, Natives")

grid.arrange(l, n, ncol=1)

For blind chironomy:

A couple of phrases natives had more trouble with. Could be that they are less conscious of the frequency curve?

Vocal Imitation

Not too much difference. Natives have more variation.

li <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% learners$id) %>%
              filter(condition=='imitation') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Imitation, Learners")

ni <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% natives$id) %>%
              filter(condition=='imitation') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Imitation, Natives")

grid.arrange(li, ni, ncol=1)

Vocal Readinig

Not too much difference. Natives have more variation. Non-natives seemed to have issues with 10, 10bis, 21.


li <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% learners$id) %>%
              filter(condition=='lecture') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Lecture, Learners")

ni <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% natives$id) %>%
              filter(condition=='lecture') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Lecture, Natives")

grid.arrange(li, ni, ncol=1)

Guided Chironomy - musicians vs non-musicians

Musicians don’t do better for guided chironomy

mg <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% musicians$id) %>%
              filter(condition=='guide') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Guided Chironomy, Musicians")

ng <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% nonmus$id) %>%
              filter(condition=='guide') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Guided Chironomy, Non-musicians")

grid.arrange(mg, ng, ncol=1)

Blind Chironomy - musicians vs non-musicians

We don’t learn much new here. Musicians do better for some phrases than others.

mb <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% musicians$id) %>%
              filter(condition=='blind') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Blind Chironomy, Musicians")

nb <- long_data %>% filter(metrics== 'corr_notiming' | metrics == 'corr') %>%
              filter(subject %in% nonmus$id) %>%
              filter(condition=='blind') %>%
              mutate(pid = fct_relevel(pid, "2", "2bis", "7", "7bis", "8", "8bis",
                           "10", "10bis", "11", "11bis", "21", "21bis")) %>%
              ggplot(aes(x=pid, y=score)) +
              geom_boxplot(aes(fill = metrics)) +
              scale_y_continuous(breaks=seq(-0.8, 1, by=.2)) + 
              scale_fill_manual(name = "Comparison type", 
                                  labels = c("With timing", "No timing"),
                                  values=wes_palette("Moonrise3")) +
              labs(title="Correlation, timing vs no-timing", subtitle="Blind Chironomy, Non-musicians")

grid.arrange(mb, nb, ncol=1)

LS0tCnRpdGxlOiAiUGlsb3QgUGxvdHMgU3RvcnkiCm91dHB1dDogCiAgIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdG9jOiB5ZXMKLS0tCgojIFN1bW1hcnkKCiogR3VpZGVkIGNoaXJvbm9teSBlbmFiYmxlcyBub24tbmF0aXZlcyB0byBnbyBiZXlvbmQgdGhlIGNhcGFjaXRpZXMgb2YgdGhlaXIgYWN0dWFsIHZvaWNlLiBGb3IgY2VydGFpbiBwaHJhc2VzLCBub24tbmF0aXZlcyBoYWQgaGlnaGVyIG1lZGlhbiBzY29yZXMgaW4gZ3VpZGVkIGNoaXJvbm9teSB0aGFuIGluIHZvY2FsIGltaXRhdGlvbgoqIENvbnRyb2xsaW5nIHRpbWluZyBhdCB0aGUgc2FtZSB0aW1lIGlzIG1vcmUgZGlmZmljdWx0CiAgKiBNb3N0IHBlb3BsZSBoYWQgdHJvdWJsZSBmaW5kaW5nIGJvdGggdGhlIGNvcnJlY3QgcGl0Y2ggYW5kIHRpbWluZyBhdCB0aGUgc2FtZSB0aW1lIHdoZW4gbm90LWd1aWRlZAogICogRm9yIHVuZ3VpZGVkLCBtdXNpY2lhbnMgZGlkIGJldHRlciBmb3Igc29tZSBwaHJhc2VzIGJ1dCBub3QgYWxsLiAKKiBEaWZmZXJlbmNlcyBiZXR3ZWVuIG5hdGl2ZXMgYW5kIG5vbi1uYXRpdmVzIGluIHRoaXMgc3R1ZHkgYXJlIGZhaXJseSBzbWFsbCwgbGltaXRlZCB0byBjZXJ0YWluIHBocmFzZXMKICAqIEZvciByZWFkaW5nLCBtb3N0IGRpZmZlcmVuY2VzIHByb251bmNpYXRpb24gYW5kIHJlZmVyZW5jZSBkdXJpbmcgcmVhZGluZyBhcmUgZHVlIHRvIHRpbWluZyB2YXJpYXRpb24gYW5kIGFyZSBuZXV0cmFsaXplZCB3aGVuIHRpbWluZyBpcyBhbGlnbmVkLiBGb3Igbm9uLW5hdGl2ZXMsIHRoZXJlIGFyZSBtb3JlIHBpdGNoIGRpZmZlcmVuY2VzLgoKR3VpZGVkIGNoaXJvbm9teSBjYW4gYmUgYSB3YXkgZm9yIG5vbi1uYXRpdmVzIHRvIHByYWN0aWNlLiBTdWNoIGludGVydmVudGlvbiBzaG91bGQgZm9jdXMgb24gcGhyYXNlcyB3aGVyZSB0aGV5IGhhdmUgdHJvdWJsZS4gRGVzaWduIG9mIGludGVyZmFjZSBzaG91bGQgY29uc2lkZXIgb3RoZXIgd2F5cyBvZiBjb250cm9sbGluZyB0aW1pbmcuIEZvbGxvd3VwIHN0dWRpZXMgc2hvdWxkIHdvcmsgd2l0aCBsZXNzIGFkdmFuY2VkIGxlYXJuZXJzLiAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFLCBtZXNzYWdlcz1GQUxTRX0KbGlicmFyeSgidGlkeXZlcnNlIikKbGlicmFyeSgid2VzYW5kZXJzb24iKQpsaWJyYXJ5KCJncmlkRXh0cmEiKQoKIyBMb2FkIHRoZSBzY29yZSBkYXRhCnZvaWNlX2RhdGEgPC0gcmVhZFJEUygiLi4vZGF0YS8yMV8wMi1zdHVkeS9zYXZlZC92b2ljZV9zY29yZXMucmRzIikKZ2VzdHNfZGF0YSA8LSByZWFkUkRTKCIuLi9kYXRhLzIxXzAyLXN0dWR5L3NhdmVkL2dlc3Rfc2NvcmVzLnJkcyIpCgojIE1vZGlmeSBhbmQgY29tYmluZSBpbnRvIGEgYmlnIHRpYmJsZQpnZXN0c19kYXRhIDwtIGdlc3RzX2RhdGEgJT4lIHNlbGVjdChzdWJqZWN0LCB0eXBlLCBwaWQsIG9yZGVyLCBwaHJhc2UsIGlkLCBjb3JyLCBjb3JyX3BzZywgcm1zZSwgcm1zZV9wc2csIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JyX25vdGltaW5nLCBjb3JyX3BzZ19ub3RpbWluZywgcm1zZV9ub3RpbWluZywgcm1zZV9wc2dfbm90aW1pbmcpICU+JQogICAgICAgICAgICAgIG11dGF0ZShjb25kaXRpb249dHlwZSkgJT4lIG11dGF0ZSh0eXBlPSJnZXN0dXJlIikKdm9pY2VfZGF0YSA8LSB2b2ljZV9kYXRhICU+JSBzZWxlY3Qoc3ViamVjdCwgdHlwZSwgcGlkLCBvcmRlciwgcGhyYXNlLCBpZCwgY29yciwgY29ycl9wc2csIHJtc2UsIHJtc2VfcHNnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ycl9ub3RpbWluZywgY29ycl9wc2dfbm90aW1pbmcsIHJtc2Vfbm90aW1pbmcsIHJtc2VfcHNnX25vdGltaW5nKSAlPiUKICAgICAgICAgICAgICBtdXRhdGUoY29uZGl0aW9uPXR5cGUpICU+JSBtdXRhdGUodHlwZT0idm9pY2UiKQoKYWxsX2RhdGEgPC0gYmluZF9yb3dzKGdlc3RzX2RhdGEsIHZvaWNlX2RhdGEpCgojIFN1YmplY3RzIGFuZCB0eXBlcwpzdWJqZWN0cyA8LSByZWFkX3RzdigiLi4vZGF0YS8yMV8wMi1zdHVkeS9zdWJqZWN0cy50c3YiKQpuYXRpdmVzIDwtIHN1YmplY3RzICU+JSBmaWx0ZXIobHZsX2ZyZW5jaCA9PSAiTiIpCmxlYXJuZXJzIDwtIHN1YmplY3RzICU+JSBmaWx0ZXIobHZsX2ZyZW5jaCAhPSAiTiIpCm11c2ljaWFucyA8LSBzdWJqZWN0cyAlPiUgZmlsdGVyKG11c2ljID09ICJZIikKbm9ubXVzIDwtIHN1YmplY3RzICU+JSBmaWx0ZXIobXVzaWMgIT0gIlkiKQpgYGAKCiMgQ29tcGFyaXNvbiBvZiBGMCBjdXJ2ZSBvbmx5LCBubyB0aW1pbmcKCiMjIE92ZXJhbGwKCkFzIGEgZmlyc3Qgc2FuaXR5IGNoZWNrLCBsZXQncyB1c2UgdGhlIHNhbWUgY29tcGFyaXNvbiBtZXRob2RzIGFzIGQnQWxlc3NhbmRybyAyMDExLiBUaGV5IHRvb2sgdGhlIGNvcnJlbGF0aW9uIGFuZCB0aGUgUk1TRSBvZiB2b2NhbCBhbmQgY2hpcm9ub21pYyBpbWl0YXRpb25zIHdpdGggdGhlIHJlZmVyZW5jZSBmMCBjdXJ2ZS4gCgoqIE1lZGlhbiBmb3Igdm9jYWwgaW1pdGF0aW9uOiA+MC45IGNvcnJlbGF0aW9uLCA8MS41U1QgUk1TRQoqIE1lZGlhbiBmb3IgY2hpcm9ub21pYyBpbWl0YXRpb246ID4wLjggY29ycmVsYXRpb24sIDwyLjVTVCBSTVNFCgpGb3Igb3VyIGRhdGE6CmBgYHtyfQphbGxfZGF0YSAlPiUgZmlsdGVyKGNvbmRpdGlvbj09ImltaXRhdGlvbiIpICU+JSBwdWxsKGNvcnJfbm90aW1pbmcpICU+JSBtZWRpYW4oKSAlPiUgCiAgcm91bmQoMykgJT4lIHBhc3RlMCgiOiBNZWRpYW4gY29ycmVsYXRpb24gb2Ygdm9jYWwgaW1pdGF0aW9uIikKCmFsbF9kYXRhICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iZ3VpZGUiKSAlPiUgcHVsbChjb3JyX25vdGltaW5nKSAlPiUgbWVkaWFuKCkgJT4lCiAgcm91bmQoMykgJT4lIHBhc3RlMCgiOiBNZWRpYW4gY29ycmVsYXRpb24gb2YgZ3VpZGVkIGNoaXJvbm9taWMgaW1pdGF0aW9uIikKCmFsbF9kYXRhICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iYmxpbmQiKSAlPiUgcHVsbChjb3JyX25vdGltaW5nKSAlPiUgbWVkaWFuKCkgJT4lIAogIHJvdW5kKDMpICU+JSBwYXN0ZTAoIjogTWVkaWFuIGNvcnJlbGF0aW9uIG9mIGJsaW5kIGNoaXJvbm9taWMgaW1pdGF0aW9uIikKCmFsbF9kYXRhICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iaW1pdGF0aW9uIikgJT4lIHB1bGwocm1zZV9ub3RpbWluZykgJT4lIG1lZGlhbigpICU+JSAKICByb3VuZCgzKSAlPiUgcGFzdGUwKCI6IE1lZGlhbiBSTVNFIG9mIHZvY2FsIGltaXRhdGlvbiIpCgphbGxfZGF0YSAlPiUgZmlsdGVyKGNvbmRpdGlvbj09Imd1aWRlIikgJT4lIHB1bGwocm1zZV9ub3RpbWluZykgJT4lIG1lZGlhbigpICU+JQogIHJvdW5kKDMpICU+JSBwYXN0ZTAoIjogTWVkaWFuIFJNU0Ugb2YgZ3VpZGVkIGNoaXJvbm9taWMgaW1pdGF0aW9uIikKCmFsbF9kYXRhICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iYmxpbmQiKSAlPiUgcHVsbChybXNlX25vdGltaW5nKSAlPiUgbWVkaWFuKCkgJT4lIAogIHJvdW5kKDMpICU+JSBwYXN0ZTAoIjogTWVkaWFuIFJNU0Ugb2YgYmxpbmQgY2hpcm9ub21pYyBpbWl0YXRpb24iKQpgYGAKCkluIGQnQWxlc3NhbmRybyAyMDExLCB0aGUgY2hpcm9ub21pYyBpbWl0YXRpb24gd2FzIG5vbi1ndWlkZWQuIFRoZSB3b3JzZSBwZXJmb3JtYW5jZSBmb3Igbm9uLWd1aWRlZCBpbWl0YXRpb24gZm9yIG91ciBzdHVkeSBtYXkgYmUgZXhwbGFpbmVkIGJ5IHRoZSBhZGRlZCBkaWZmaWN1bHR5IG9mIGZpbmRpbmcgdGhlIGludG9uYXRpb24gY3VydmUgYW5kIHRoZSBjb3JyZWN0IHRpbWluZyBjb250cm9sLgoKU2xpZ2h0bHkgYmV0dGVyIHNjb3JlcyBhcmlzZSBmb3IgY2hpcm9ub21pYyBpbWl0YXRpb24gd2hlbiB3ZSB1c2UgdGhlIHN0eWxpemVkIGYwIGN1cnZlIGFzIGEgcmVmZXJlbmNlLiBTdHlsaXphdGlvbiBjdXJ2ZSBzaW1wbGlmaWVzIHRoZSBmMCBjdXJ2ZSBpbnRvIHN0cmFpZ2h0IGxpbmUgc2VnbWVudHMgYmFzZWQgb24gYSBwZXJjZXB0dWFsIG1vZGVsLiBUaGUgc3R5bGl6YXRpb24gcmVtb3ZlcyBtaWNyb3Byb3NvZGljIGRldGFpbHMgcHJlc2VudCBpbiBuYXR1cmFsIHZvY2FsIHByb251bmNpYXRpb25zIHRoYXQgYXJlIG5vdCBwZXJjZXB0dWFsbHkgc2FsaWVudC4gUmVzeW50aGVzaXplZCB1dHRlcmFuY2VzIHdpdGggZjAgcmVwbGFjZWQgYnkgdGhlIHN0eWxpemVkIHZlcnNpb24gYXJlIHBlcmNlcHR1YWxseSBpZGVudGljYWwgdG8gdGhlIG9yaWdpbmFsLiAKCkJlbG93IGFyZSBhZ2dyZWdhdGUgcmVzdWx0cyBmb3IgYWxsIGRhdGEgdXNpbmcgdGhlIHR3byB0eXBlcyBvZiByZWZlcmVuY2VzOgoKYGBge3J9CiMgQ29ycmVsYXRpb24Kb3ZlcmFsbF9wc2dfbm90aW1pbmcgPC0gYWxsX2RhdGEgJT4lIGdncGxvdChhZXMoeD1jb25kaXRpb24sIHk9Y29ycl9wc2dfbm90aW1pbmcpKSArIAogICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPWNvbmRpdGlvbiksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz13ZXNfcGFsZXR0ZSgiTW9vbnJpc2UzIikpICsKICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKC0wLjgsIDEsIGJ5PTAuMikpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uLCBObyB0aW1pbmciLCBzdWJ0aXRsZT0iU3R5bGl6ZWQgcmVmZXJlbmNlIiwKICAgICAgICAgICAgICB4PSJDb25kaXRpb24iLCB5PSJDb3JyZWxhdGlvbiIpIAoKb3ZlcmFsbF9ub3RpbWluZyA8LSBhbGxfZGF0YSAlPiUgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbiwgeT1jb3JyX25vdGltaW5nKSkgKyAKICAgICAgICAgICAgIGdlb21fYm94cGxvdChhZXMoZmlsbD1jb25kaXRpb24pLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9d2VzX3BhbGV0dGUoIk1vb25yaXNlMyIpKSArCiAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoLTAuOCwgMSwgYnk9MC4yKSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iIiwgc3VidGl0bGU9Ik9yaWdpbmFsIHJlZmVyZW5jZSIsCiAgICAgICAgICAgICAgeD0iQ29uZGl0aW9uIiwgeT0iQ29ycmVsYXRpb24iKSAKCiMgUk1TRQpvdmVyYWxsX3BzZ19ybXNlX25vdGltaW5nIDwtIGFsbF9kYXRhICU+JSBnZ3Bsb3QoYWVzKHg9Y29uZGl0aW9uLCB5PXJtc2VfcHNnX25vdGltaW5nKSkgKyAKICAgICAgICAgICAgIGdlb21fYm94cGxvdChhZXMoZmlsbD1jb25kaXRpb24pLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9d2VzX3BhbGV0dGUoIk1vb25yaXNlMiIpKSArCiAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLCA4LCBieT0xKSkgKyAKICAgICAgICAgICAgIGxhYnModGl0bGU9IlJNU0UgU2NvcmVzLCBObyB0aW1pbmciLCBzdWJ0aXRsZT0iU3R5bGl6ZWQgcmVmZXJlbmNlIiwKICAgICAgICAgICAgICB4PSJDb25kaXRpb24iLCB5PSJDb3JyZWxhdGlvbiIpIAoKb3ZlcmFsbF9ybXNlX25vdGltaW5nIDwtIGFsbF9kYXRhICU+JSBnZ3Bsb3QoYWVzKHg9Y29uZGl0aW9uLCB5PXJtc2Vfbm90aW1pbmcpKSArIAogICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPWNvbmRpdGlvbiksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz13ZXNfcGFsZXR0ZSgiTW9vbnJpc2UyIikpICsKICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsIDgsIGJ5PTEpKSArIAogICAgICAgICAgICAgbGFicyh0aXRsZT0iIiwgc3VidGl0bGU9Ik9yaWdpbmFsIHJlZmVyZW5jZSIsCiAgICAgICAgICAgICAgeD0iQ29uZGl0aW9uIiwgeT0iQ29ycmVsYXRpb24iKSAKCmdyaWQuYXJyYW5nZShvdmVyYWxsX3BzZ19ub3RpbWluZywgb3ZlcmFsbF9ub3RpbWluZywgb3ZlcmFsbF9wc2dfcm1zZV9ub3RpbWluZywgb3ZlcmFsbF9ybXNlX25vdGltaW5nLCBuY29sPTIpCgpgYGAKCmBgYHtyfQphbGxfZGF0YSAlPiUgZmlsdGVyKGNvbmRpdGlvbj09ImltaXRhdGlvbiIpICU+JSBwdWxsKGNvcnJfbm90aW1pbmcpICU+JSBtZWRpYW4oKSAlPiUgCiAgcm91bmQoMykgJT4lIHBhc3RlMCgiOiBNZWRpYW4gY29ycmVsYXRpb24gb2Ygdm9jYWwgaW1pdGF0aW9uIikKCmFsbF9kYXRhICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iZ3VpZGUiKSAlPiUgcHVsbChjb3JyX3BzZ19ub3RpbWluZykgJT4lIG1lZGlhbigpICU+JQogIHJvdW5kKDMpICU+JSBwYXN0ZTAoIjogTWVkaWFuIGNvcnJlbGF0aW9uIG9mIGNoaXJvbm9taWMgaW1pdGF0aW9uIikKCmFsbF9kYXRhICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iaW1pdGF0aW9uIikgJT4lIHB1bGwocm1zZV9ub3RpbWluZykgJT4lIG1lZGlhbigpICU+JSAKICByb3VuZCgzKSAlPiUgcGFzdGUwKCI6IE1lZGlhbiBSTVNFIG9mIHZvY2FsIGltaXRhdGlvbiIpCgphbGxfZGF0YSAlPiUgZmlsdGVyKGNvbmRpdGlvbj09Imd1aWRlIikgJT4lIHB1bGwocm1zZV9wc2dfbm90aW1pbmcpICU+JSBtZWRpYW4oKSAlPiUKICByb3VuZCgzKSAlPiUgcGFzdGUwKCI6IE1lZGlhbiBSTVNFIG9mIGNoaXJvbm9taWMgaW1pdGF0aW9uIikKYGBgCgpGb3IgdGhlIHJlc3Qgb2YgdGhlIGNvbXBhcmlzb24sIHdlIHdpbGwgYmUgdXNpbmcgdGhlIHN0eWxpemVkIHZlcnNpb24gYXMgYSByZWZlcmVuY2UgZm9yIHRoZSBjaGlyb25vbWljIGltaXRhdGlvbnMgYW5kIHRoZSBvcmlnaW5hbCBmMCBjdXJ2ZSBmb3IgdGhlIHZvY2FsIHByb251bmNpYXRpb25zLiBDaGlyb25vbWljIHByb251bmNpYXRpb25zIGFyZSBhbHdheXMgYSBzdHlsaXphdGlvbiBiZWNhdXNlIGl0IGlzIGJvdGggZGlmZmljdWx0IGFuZCB1bm5jZXNzYXJ5IGZvciB0aGUgaGFuZHMgdG8gcHJvZHVjZSB0aGUgc2FtZSBtaWNyby1wcm9zb2RpYyBhcnRpZmFjdHMgYXMgdGhlIHZvaWNlLgoKYGBge3J9Cm5vdGltaW5nX2dlc3RfZGF0YSA8LSBhbGxfZGF0YSAlPiUgZmlsdGVyKHR5cGU9PSdnZXN0dXJlJykgJT4lIAogICAgICAgICAgICAgICAgIG11dGF0ZShjb3JyX25vdGltaW5nID0gY29ycl9wc2dfbm90aW1pbmcsIHJtc2Vfbm90aW1pbmc9cm1zZV9wc2dfbm90aW1pbmcpIApub3RpbWluZ192b2ljZV9kYXRhIDwtIGFsbF9kYXRhICU+JWZpbHRlcih0eXBlPT0idm9pY2UiKSAgICAgICAgICAKbm90aW1pbmdfZGF0YSA8LWJpbmRfcm93cyhub3RpbWluZ19nZXN0X2RhdGEsIG5vdGltaW5nX3ZvaWNlX2RhdGEpCmBgYAoKIyMgTmF0aXZlIHZzIE5vbi1uYXRpdmVzCgpEaWZmZXJlbmNlcyBhcmUgc2xpZ2h0IGJldHdlZW4gdGhlIGxlYXJuZXIgYW5kIG5hdGl2ZSBncm91cHMgaW4gdGhpcyBzdHVkeS4gVGhpcyBwYXJ0aWN1bGFyIGdyb3VwIG9mIGxlYXJuZXJzIGhhdmUgYWxsIHRha2VuIGEgY2xhc3Mgb24gRnJlbmNoIGludG9uYXRpb24gYW5kIGhhdmUgZW5jb3VudGVyZWQgdGhlIHBocmFzZXMgdXNlZCBpbiB0aGUgc3R1ZHkuIFRoZWlyIHBlcmZvcm1hbmNlIGZvciBjaGlyb25vbWljIGltaXRhdGlvbiBpcyBldmVuIHNsaWdodGx5IGJldHRlciB0aGFuIHRoYXQgb2YgbmF0aXZlcyAocHJvYmFibHkgbm90IHNpZ25pZmljYW50KS4gCgpOYXRpdmVzIGhhdmUgc2xpZ2h0bHkgYmV0dGVyIHZvY2FsIHNjb3Jlcy4gVGhlaXIgcmVhZGluZyBpcyBhbHNvIG1vcmUgc2ltaWxhciB0byB0aGUgb3JpZ2luYWxzIHdoZW4gdGltaW5nIGlzIG5vdCB0YWtlbiBpbnRvIGFjY291bnQuCgpgYGB7cn0KbGVhcm5lcnNfYm94IDwtIG5vdGltaW5nX2RhdGEgJT4lIGZpbHRlcihzdWJqZWN0ICVpbiUgbGVhcm5lcnMkaWQpICU+JQogIGdncGxvdChhZXMoeD1jb25kaXRpb24sIHk9Y29ycl9ub3RpbWluZykpICsgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPWNvbmRpdGlvbiksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiR3JhbmRCdWRhcGVzdDIiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKC0wLjgsIDEsIGJ5PTAuMikpICsKICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiBTY29yZXMsIG5vIHRpbWluZyIsIHN1YnRpdGxlPSJMZWFybmVycyIpIAogICAgICAgICAgICAgICAgICAgIApuYXRpdmVzX2JveCA8LSBub3RpbWluZ19kYXRhICU+JSBmaWx0ZXIoc3ViamVjdCAlaW4lIG5hdGl2ZXMkaWQpICU+JQogIGdncGxvdChhZXMoeD1jb25kaXRpb24sIHk9Y29ycl9ub3RpbWluZykpICsgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPWNvbmRpdGlvbiksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiR3JhbmRCdWRhcGVzdDIiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKC0wLjgsIDEsIGJ5PTAuMikpICsKICBsYWJzKHRpdGxlPSIiLCBzdWJ0aXRsZT0iTmF0aXZlcyIpICAgICAgICAgICAgICAgICAgICAKCmxlYXJuZXJzX2JveF9ybXNlIDwtIG5vdGltaW5nX2RhdGEgJT4lIGZpbHRlcihzdWJqZWN0ICVpbiUgbGVhcm5lcnMkaWQpICU+JQogIGdncGxvdChhZXMoeD1jb25kaXRpb24sIHk9cm1zZV9ub3RpbWluZykpICsgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPWNvbmRpdGlvbiksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiR3JhbmRCdWRhcGVzdDEiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsIDgsIGJ5PTEpKSArIAogIGxhYnModGl0bGU9IlJNU0UgU2NvcmVzLCBubyB0aW1pbmciLCBzdWJ0aXRsZT0iTGVhcm5lcnMiKSAKICAgICAgICAgICAgICAgICAgICAKbmF0aXZlc19ib3hfcm1zZSA8LSBub3RpbWluZ19kYXRhICU+JSBmaWx0ZXIoc3ViamVjdCAlaW4lIG5hdGl2ZXMkaWQpICU+JQogIGdncGxvdChhZXMoeD1jb25kaXRpb24sIHk9cm1zZV9ub3RpbWluZykpICsgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPWNvbmRpdGlvbiksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiR3JhbmRCdWRhcGVzdDEiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsIDgsIGJ5PTEpKSArIAogIGxhYnModGl0bGU9IiIsIHN1YnRpdGxlPSJOYXRpdmVzIikgICAgICAgICAgICAgICAgICAgIAoKZ3JpZC5hcnJhbmdlKGxlYXJuZXJzX2JveCwgbmF0aXZlc19ib3gsIGxlYXJuZXJzX2JveF9ybXNlLCBuYXRpdmVzX2JveF9ybXNlLCBuY29sPTIpIApgYGAKCiMjIE11c2ljaWFucyB2cyBOb24tbXVzaWNpYW5zCgo3IG9mIHRoZSAxMCBzdWJqZWN0cyBpbiBkJ0FsZXNzYW5kcm8gMjAxMSBoYWQgYSBtdXNpY2FsIHByYWN0aWNlLiBJdCBtYXkgaGF2ZSBoZWxwZWQgdGhlaXIgcGVyZm9ybWFuY2UgaW4gdGhlIGNoaXJvbm9taWMgY29uZGl0aW9uLiBJbiBvdXIgc3R1ZHksIDQgb2YgdGhlIDEwIHN1YmplY3RzIHBsYXkgbXVzaWMgb3Igc2luZy4gTXVzaWNpYW5zIGhhZCBzbGlnaHRseSBiZXR0ZXIgc2NvcmVzIGZvciB0aGUgYmxpbmQgY2hpcm9ub21pYyBjb25kaXRpb24uIFRoZWlyIHJlc3VsdHMgYXJlIG5vdCBkaWZmZXJlbnQgZnJvbSBub24tbXVzaWNpYW5zIGluIHRoZSBvdGhlciBjb25kaXRpb25zLgoKYGBge3J9Cm5vdGltaW5nX2RhdGEgJT4lIGZpbHRlcihzdWJqZWN0ICVpbiUgbXVzaWNpYW5zJGlkICYgY29uZGl0aW9uPT0iYmxpbmQiKSAlPiUgcHVsbChjb3JyX3BzZ19ub3RpbWluZykgJT4lIG1lZGlhbigpICU+JSAKICByb3VuZCgzKSAlPiUgcGFzdGUwKCI6IE1lZGlhbiBjb3JyZWxhdGlvbiBvZiBibGluZCBjaGlyb25vbXkgLSBNdXNpY2lhbnMiKQoKbm90aW1pbmdfZGF0YSAlPiUgZmlsdGVyKHN1YmplY3QgJWluJSBub25tdXMkaWQgJiBjb25kaXRpb249PSJibGluZCIpICU+JSBwdWxsKGNvcnJfcHNnX25vdGltaW5nKSAlPiUgbWVkaWFuKCkgJT4lIAogIHJvdW5kKDMpICU+JSBwYXN0ZTAoIjogTWVkaWFuIGNvcnJlbGF0aW9uIG9mIGJsaW5kIGNoaXJvbm9teSAtIE5vbi1tdXNpY2lhbnMiKQoKbm90aW1pbmdfZGF0YSAlPiUgZmlsdGVyKHN1YmplY3QgJWluJSBtdXNpY2lhbnMkaWQgJiBjb25kaXRpb249PSJibGluZCIpICU+JSBwdWxsKHJtc2VfcHNnX25vdGltaW5nKSAlPiUgbWVkaWFuKCkgJT4lIAogIHJvdW5kKDMpICU+JSBwYXN0ZTAoIjogTWVkaWFuIGNvcnJlbGF0aW9uIG9mIGJsaW5kIGNoaXJvbm9teSAtIE11c2ljaWFucyIpCgpub3RpbWluZ19kYXRhICU+JSBmaWx0ZXIoc3ViamVjdCAlaW4lIG5vbm11cyRpZCAmIGNvbmRpdGlvbj09ImJsaW5kIikgJT4lIHB1bGwocm1zZV9wc2dfbm90aW1pbmcpICU+JSBtZWRpYW4oKSAlPiUgCiAgcm91bmQoMykgJT4lIHBhc3RlMCgiOiBNZWRpYW4gY29ycmVsYXRpb24gb2YgYmxpbmQgY2hpcm9ub215IC0gTm9uLW11c2ljaWFucyIpCmBgYAoKCmBgYHtyfQptdXNpY2lhbnNfYm94IDwtIG5vdGltaW5nX2RhdGEgJT4lIGZpbHRlcihzdWJqZWN0ICVpbiUgbXVzaWNpYW5zJGlkKSAlPiUKICBnZ3Bsb3QoYWVzKHg9Y29uZGl0aW9uLCB5PWNvcnJfbm90aW1pbmcpKSArIGdlb21fYm94cGxvdChhZXMoZmlsbD1jb25kaXRpb24pLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIkNoZXZhbGllcjEiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKC0wLjgsIDEsIGJ5PTAuMikpICsKICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiBTY29yZXMsIG5vIHRpbWluZyIsIHN1YnRpdGxlPSJNdXNpY2lhbnMiKQogICAgICAgICAgICAgICAgICAgIApub25tdXNfYm94IDwtIG5vdGltaW5nX2RhdGEgJT4lIGZpbHRlcihzdWJqZWN0ICVpbiUgbm9ubXVzJGlkKSAlPiUKICBnZ3Bsb3QoYWVzKHg9Y29uZGl0aW9uLCB5PWNvcnJfbm90aW1pbmcpKSArIGdlb21fYm94cGxvdChhZXMoZmlsbD1jb25kaXRpb24pLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIkNoZXZhbGllcjEiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKC0wLjgsIDEsIGJ5PTAuMikpICsKICBsYWJzKHRpdGxlPSIiLCBzdWJ0aXRsZT0iTm9uLW11c2ljaWFucyIpICAgICAgICAgICAgICAgICAgICAKIAptdXNpY2lhbnNfYm94X3Jtc2UgPC0gbm90aW1pbmdfZGF0YSAlPiUgZmlsdGVyKHN1YmplY3QgJWluJSBtdXNpY2lhbnMkaWQpICU+JQogIGdncGxvdChhZXMoeD1jb25kaXRpb24sIHk9cm1zZV9ub3RpbWluZykpICsgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPWNvbmRpdGlvbiksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwyIikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLCA4LCBieT0xKSkgKyAKICBsYWJzKHRpdGxlPSJSTVNFIFNjb3Jlcywgbm8gdGltaW5nIiwgc3VidGl0bGU9Ik11c2ljaWFucyIpCiAgICAgICAgICAgICAgICAgICAgCm5vbm11c19ib3hfcm1zZSA8LSBub3RpbWluZ19kYXRhICU+JSBmaWx0ZXIoc3ViamVjdCAlaW4lIG5vbm11cyRpZCkgJT4lCiAgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbiwgeT1ybXNlX25vdGltaW5nKSkgKyBnZW9tX2JveHBsb3QoYWVzKGZpbGw9Y29uZGl0aW9uKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJSb3lhbDIiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsIDgsIGJ5PTEpKSArIAogIGxhYnModGl0bGU9IiIsIHN1YnRpdGxlPSJOb24tbXVzaWNpYW5zIikgICAgIAoKZ3JpZC5hcnJhbmdlKG11c2ljaWFuc19ib3gsIG5vbm11c19ib3gsIG11c2ljaWFuc19ib3hfcm1zZSwgbm9ubXVzX2JveF9ybXNlLCBuY29sPTIpCmBgYAoKIyMgQnkgUGhyYXNlCgpGb3IgbW9zdCBwaHJhc2VzLCBndWlkZWQgY2hpcm9ub215IGFuZCB2b2NhbCBpbWl0YXRpb24gaGFkIGNvbXBhcmFibGUgc2NvcmVzIHdoZW4gdGltaW5nIGlzIG5vdCB0YWtlbiBpbnRvIGFjY291bnQuIEJvdGggaGFkIGhpZ2hlciB0aGFuID4wLjkgbWVkaWFuIGNvcnJlbGF0aW9uIGZvciBtb3N0IHBocmFzZXMsIGFuZCBiZXR3ZWVuIDAuNSAmIDIuNVNUIG1lZGlhbiBSTVNFLgoKRm9yIGhhbGYgb2YgdGhlIHBocmFzZXMgKGUuZy4gMmJpcywgNywgOCwgMTAsIDExYmlzLCAyMWJpcyksIGd1aWRlZCBjaGlyb25vbXkgaGFkIGhpZ2hlciBtZWRpYW4gc2NvcmVzIGZvciBjb3JyZWxhdGlvbi4gU29tZSBvZiB0aGVzZSBwaHJhc2VzICgxMCwgMjFiaXMpLCBndWlkZWQgY2hpcm9ub215IGFsc28gaGFkIGEgYmV0dGVyIChsb3dlcikgUk1TRSBzY29yZS4KCkJsaW5kIGNoaXJvbm9teSB2YXJpZWQgd2lkZWx5IGFjcm9zcyBwaHJhc2VzIHRoZSBwaHJhc2VzLiBTb21lIHBocmFzZXMgd2VyZSBub3RhYmx5IG1vcmUgZGlmZmljdWx0IGV2ZW4gaW4gdGhlIGd1aWRlZCBjaGlyb25vbXkgY29uZGl0aW9uLgoKYGBge3J9Cm5vdGltaW5nX2RhdGEgJT4lCiAgbXV0YXRlKHBpZCA9IGZjdF9yZWxldmVsKHBpZCwgIjIiLCAiMmJpcyIsICI3IiwgIjdiaXMiLCAiOCIsICI4YmlzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwIiwgIjEwYmlzIiwgIjExIiwgIjExYmlzIiwgIjIxIiwgIjIxYmlzIikpICU+JQogIGdncGxvdChhZXMoeD1waWQsIHk9Y29ycl9ub3RpbWluZywgZmlsbD1jb25kaXRpb24pKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoLTAuOCwgMSwgYnk9MC4yKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aD0wLjcpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIk1vb25yaXNlMyIpKSArCiAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gU2NvcmVzLCBubyB0aW1pbmcgLSBhbGwgc3ViamVjdHMiLCAKICAgICAgICAgICAgc3VidGl0bGU9Ikdyb3VwZWQgYnkgcGhyYXNlIiwKICAgICAgICAgICAgeD0iUGhyYXNlIGlkIiwgeT0iQ29ycmVsYXRpb24iKSAjKyB0aGVtZShhc3BlY3QucmF0aW89MC40KQpgYGAKCmBgYHtyfQpub3RpbWluZ19kYXRhICU+JQogIG11dGF0ZShwaWQgPSBmY3RfcmVsZXZlbChwaWQsICIyIiwgIjJiaXMiLCAiNyIsICI3YmlzIiwgIjgiLCAiOGJpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMCIsICIxMGJpcyIsICIxMSIsICIxMWJpcyIsICIyMSIsICIyMWJpcyIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cGlkLCB5PXJtc2Vfbm90aW1pbmcsIGZpbGw9Y29uZGl0aW9uKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aD0wLjcpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIk1vb25yaXNlMSIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgOCwgYnk9MSkpICsgCiAgbGFicyh0aXRsZT0iUk1TRSBTY29yZXMsIG5vIHRpbWluZyAtIGFsbCBzdWJqZWN0IiwgCiAgICAgICAgICAgIHN1YnRpdGxlPSJHcm91cGVkIGJ5IHBocmFzZSIsCiAgICAgICAgICAgIHg9IlBocmFzZSBpZCIsIHk9IlJNU0UiKSAjKyB0aGVtZShhc3BlY3QucmF0aW89MC40KQpgYGAKCiMjIFBocmFzZSBhbmQgU3ViamVjdCBHcm91cHMKCiMjIyBOYXRpdmUvTm9uLW5hdGl2ZQoKTmF0aXZlcyBhbmQgbGVhcm5lcnMgcGVyZm9ybWVkIHF1aXRlIGRpZmZlcmVudGx5IGFjcm9zcyB0aGUgZGlmZmVyZW50IHBocmFzZXMuICAKCiogRm9yIGxlYXJuZXJzLCByZWFkaW5nIChsZWN0dXJlKSBkaWZmZXJlZCBmcm9tIHRoZSBtb2RlbCB0aGUgbW9zdCBmb3IgcGhyYXNlcyAxMCwgMTBiaXMsIDIxLgoqIEZvciBub24tbmF0aXZlcywgdGhlIG9ubHkgcGhyYXNlIHRoYXQgaGFkIG1lZGlhbiBjb3JyZWxhdGlvbiA8MC44IGluIHRoZSByZWFkaW5nIGNvbmRpdGlvbiB3YXMgMTBiaXMKKiBGb3Igc29tZSBwaHJhc2VzLCBibGluZCBjaGlyb25vbXkgaGFkIHByZXR0eSBnb29kIHNjb3JlcyAoY29ycmVsYXRpb24gPjAuOCkuIFRoZXNlIHBocmFzZXMgd2VyZSBub3QgYWxsIHRoZSBzYW1lIGZvciBuIGF0aXZlIHZzIG5vbi1uYXRpdmVzLgoqIEZvciBzb21lIHBocmFzZXMsIGluIHRoZSBibGluZCBjaGlyb25vbXkgY29uZGl0aW9uLCBuYXRpdmVzIGhhZCBsb3dlciBzY29yZXMgdGhhbiBub24tbmF0aXZlcwoKSW4gZGlzY3Vzc2lvbnMgYWZ0ZXIgdGhlIHN0dWR5LCBhIGNvdXBsZSBvZiBuYXRpdmUgc3BlYWtlcnMgcmVwb3J0ZWQgbm90IGFncmVlaW5nIHdpdGggdGhlIHJlZmVyZW5jZSBpbnRvbmF0aW9uIGN1cnZlIHByb3ZpZGVkIGZvciB0aGUgZ3VpZGVkIGNoaXJvbm9teSBjb25kaXRpb24uCgpgYGB7cn0KY19sIDwtIG5vdGltaW5nX2RhdGEgJT4lIGZpbHRlcihzdWJqZWN0ICVpbiUgbGVhcm5lcnMkaWQpICU+JQogIG11dGF0ZShwaWQgPSBmY3RfcmVsZXZlbChwaWQsICIyIiwgIjJiaXMiLCAiNyIsICI3YmlzIiwgIjgiLCAiOGJpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMCIsICIxMGJpcyIsICIxMSIsICIxMWJpcyIsICIyMSIsICIyMWJpcyIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cGlkLCB5PWNvcnJfbm90aW1pbmcsIGZpbGw9Y29uZGl0aW9uKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aD0wLjcpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoLTAuOCwgMSwgYnk9MC4yKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJNb29ucmlzZTMiKSkgKwogIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uIFNjb3Jlcywgbm8gdGltaW5nIC0gTGVhcm5lcnMiLCAKICAgICAgICAgICAgc3VidGl0bGU9Ikdyb3VwZWQgYnkgcGhyYXNlIiwKICAgICAgICAgICAgeD0iUGhyYXNlIGlkIiwgeT0iQ29ycmVsYXRpb24iKSAjKyB0aGVtZShhc3BlY3QucmF0aW89MC40KQoKY19uIDwtIG5vdGltaW5nX2RhdGEgJT4lIGZpbHRlcihzdWJqZWN0ICVpbiUgbmF0aXZlcyRpZCkgJT4lCiAgbXV0YXRlKHBpZCA9IGZjdF9yZWxldmVsKHBpZCwgIjIiLCAiMmJpcyIsICI3IiwgIjdiaXMiLCAiOCIsICI4YmlzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwIiwgIjEwYmlzIiwgIjExIiwgIjExYmlzIiwgIjIxIiwgIjIxYmlzIikpICU+JQogIGdncGxvdChhZXMoeD1waWQsIHk9Y29ycl9ub3RpbWluZywgZmlsbD1jb25kaXRpb24pKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuNykgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMC44LCAxLCBieT0wLjIpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIk1vb25yaXNlMyIpKSArCiAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gU2NvcmVzLCBubyB0aW1pbmcgLSBOYXRpdmVzIiwgCiAgICAgICAgICAgIHN1YnRpdGxlPSJHcm91cGVkIGJ5IHBocmFzZSIsCiAgICAgICAgICAgIHg9IlBocmFzZSBpZCIsIHk9IkNvcnJlbGF0aW9uIikgIysgdGhlbWUoYXNwZWN0LnJhdGlvPTAuNCkKCmdyaWQuYXJyYW5nZShjX2wsIGNfbiwgbmNvbD0xKQpgYGAKCmBgYHtyfQpyX2wgPC0gbm90aW1pbmdfZGF0YSAlPiUgZmlsdGVyKHN1YmplY3QgJWluJSBsZWFybmVycyRpZCkgJT4lCiAgbXV0YXRlKHBpZCA9IGZjdF9yZWxldmVsKHBpZCwgIjIiLCAiMmJpcyIsICI3IiwgIjdiaXMiLCAiOCIsICI4YmlzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwIiwgIjEwYmlzIiwgIjExIiwgIjExYmlzIiwgIjIxIiwgIjIxYmlzIikpICU+JQogIGdncGxvdChhZXMoeD1waWQsIHk9cm1zZV9ub3RpbWluZywgZmlsbD1jb25kaXRpb24pKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuNykgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLCA4LCBieT0xKSkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwyIikpICsKICBsYWJzKHRpdGxlPSJSTVNFIFNjb3JlcyAtIExlYXJuZXJzIiwgCiAgICAgICAgICAgIHN1YnRpdGxlPSJHcm91cGVkIGJ5IHBocmFzZSIsCiAgICAgICAgICAgIHg9IlBocmFzZSBpZCIsIHk9IlJNU0UiKSAKCnJfbiA8LSBub3RpbWluZ19kYXRhICU+JSBmaWx0ZXIoc3ViamVjdCAlaW4lIG5hdGl2ZXMkaWQpICU+JQogIG11dGF0ZShwaWQgPSBmY3RfcmVsZXZlbChwaWQsICIyIiwgIjJiaXMiLCAiNyIsICI3YmlzIiwgIjgiLCAiOGJpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMCIsICIxMGJpcyIsICIxMSIsICIxMWJpcyIsICIyMSIsICIyMWJpcyIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cGlkLCB5PXJtc2Vfbm90aW1pbmcsIGZpbGw9Y29uZGl0aW9uKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aD0wLjcpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgOCwgYnk9MSkpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlJveWFsMiIpKSArCiAgbGFicyh0aXRsZT0iUk1TRSBTY29yZXMgLSBOYXRpdmVzIiwgCiAgICAgICAgICAgIHN1YnRpdGxlPSJHcm91cGVkIGJ5IHBocmFzZSIsCiAgICAgICAgICAgIHg9IlBocmFzZSBpZCIsIHk9IlJNU0UiKSAKCmdyaWQuYXJyYW5nZShyX2wsIHJfbiwgbmNvbD0xKQpgYGAKCiMjIyBNdXNpY2lhbi9Ob24tbXVzaWNpYW4KCkluIHRlcm1zIG9mIGNvcnJlbGF0aW9uLCBtdXNpY2lhbnMgZGlkIG11Y2ggYmV0dGVyIHRoYW4gbm9uLW11c2ljaWFucyBpbiBibGluZCBjaGlyb25vbXkgZm9yIGEgZmV3IHNwZWNpZmljIHBocmFzZXMgKGUuZy4gMiwgNywgOCkuIFNvbWUgcGhyYXNlcyB3ZXJlIGRpZmZpY3VsdCBmb3IgZXZlcnlvbmUgKDEwYmlzLCAyMSksIGJ1dCBtdXNpY2lhbnMgc3RpbGwgZGlkIGJldHRlci4KCmBgYHtyfQpjX20gPC0gbm90aW1pbmdfZGF0YSAlPiUgZmlsdGVyKHN1YmplY3QgJWluJSBtdXNpY2lhbnMkaWQpICU+JQogIG11dGF0ZShwaWQgPSBmY3RfcmVsZXZlbChwaWQsICIyIiwgIjJiaXMiLCAiNyIsICI3YmlzIiwgIjgiLCAiOGJpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMCIsICIxMGJpcyIsICIxMSIsICIxMWJpcyIsICIyMSIsICIyMWJpcyIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cGlkLCB5PWNvcnJfbm90aW1pbmcsIGZpbGw9Y29uZGl0aW9uKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aD0wLjcpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoLTAuOCwgMSwgYnk9MC4yKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJNb29ucmlzZTMiKSkgKwogIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uIFNjb3Jlcywgbm8gdGltaW5nIC0gTXVzaWNpYW5zIiwgCiAgICAgICAgICAgIHN1YnRpdGxlPSJHcm91cGVkIGJ5IHBocmFzZSIsCiAgICAgICAgICAgIHg9IlBocmFzZSBpZCIsIHk9IkNvcnJlbGF0aW9uIikgIysgdGhlbWUoYXNwZWN0LnJhdGlvPTAuNCkKCmNfbm0gPC0gbm90aW1pbmdfZGF0YSAlPiUgZmlsdGVyKHN1YmplY3QgJWluJSBub25tdXMgJGlkKSAlPiUKICBtdXRhdGUocGlkID0gZmN0X3JlbGV2ZWwocGlkLCAiMiIsICIyYmlzIiwgIjciLCAiN2JpcyIsICI4IiwgIjhiaXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAiLCAiMTBiaXMiLCAiMTEiLCAiMTFiaXMiLCAiMjEiLCAiMjFiaXMiKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXBpZCwgeT1jb3JyX25vdGltaW5nLCBmaWxsPWNvbmRpdGlvbikpICsKICBnZW9tX2JveHBsb3Qod2lkdGg9MC43KSArIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKC0wLjgsIDEsIGJ5PTAuMikpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiTW9vbnJpc2UzIikpICsKICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiBTY29yZXMsIG5vIHRpbWluZyAtIE5vbi1tdXNpY2lhbnMiLCAKICAgICAgICAgICAgc3VidGl0bGU9Ikdyb3VwZWQgYnkgcGhyYXNlIiwKICAgICAgICAgICAgeD0iUGhyYXNlIGlkIiwgeT0iQ29ycmVsYXRpb24iKSAjKyB0aGVtZShhc3BlY3QucmF0aW89MC40KQoKZ3JpZC5hcnJhbmdlKGNfbSwgY19ubSwgbmNvbD0xKQpgYGAKCgpgYGB7cn0Kcl9tIDwtIG5vdGltaW5nX2RhdGEgJT4lIGZpbHRlcihzdWJqZWN0ICVpbiUgbXVzaWNpYW5zJGlkKSAlPiUKICBtdXRhdGUocGlkID0gZmN0X3JlbGV2ZWwocGlkLCAiMiIsICIyYmlzIiwgIjciLCAiN2JpcyIsICI4IiwgIjhiaXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAiLCAiMTBiaXMiLCAiMTEiLCAiMTFiaXMiLCAiMjEiLCAiMjFiaXMiKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXBpZCwgeT1ybXNlX25vdGltaW5nLCBmaWxsPWNvbmRpdGlvbikpICsKICBnZW9tX2JveHBsb3Qod2lkdGg9MC43KSArIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsIDgsIGJ5PTEpKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJSb3lhbDIiKSkgKwogIGxhYnModGl0bGU9IlJNU0UgU2NvcmVzIC0gTXVzaWNpYW5zIiwgCiAgICAgICAgICAgIHN1YnRpdGxlPSJHcm91cGVkIGJ5IHBocmFzZSIsCiAgICAgICAgICAgIHg9IlBocmFzZSBpZCIsIHk9IlJNU0UiKSAKCnJfbm0gPC0gbm90aW1pbmdfZGF0YSAlPiUgZmlsdGVyKHN1YmplY3QgJWluJSBub25tdXMkaWQpICU+JQogIG11dGF0ZShwaWQgPSBmY3RfcmVsZXZlbChwaWQsICIyIiwgIjJiaXMiLCAiNyIsICI3YmlzIiwgIjgiLCAiOGJpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMCIsICIxMGJpcyIsICIxMSIsICIxMWJpcyIsICIyMSIsICIyMWJpcyIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cGlkLCB5PXJtc2Vfbm90aW1pbmcsIGZpbGw9Y29uZGl0aW9uKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aD0wLjcpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgOCwgYnk9MSkpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlJveWFsMiIpKSArCiAgbGFicyh0aXRsZT0iUk1TRSBTY29yZXMgLSBOb25tdXMiLCAKICAgICAgICAgICAgc3VidGl0bGU9Ikdyb3VwZWQgYnkgcGhyYXNlIiwKICAgICAgICAgICAgeD0iUGhyYXNlIGlkIiwgeT0iUk1TRSIpIAoKZ3JpZC5hcnJhbmdlKHJfbSwgcl9ubSwgbmNvbD0xKQpgYGAKCgojIFRha2luZyBUaW1pbmcgaW50byBhY2NvdW50CgpGb3IgZ2VzdHVyYWwgY29tcGFyaXNvbnMsIHdlIG5lZWQgdG8gbWFrZSBzdXJlIHRoYXQgd2UgYXJlIGNvbXBhcmluZyB3aXRoIHRoZSByaWdodCBwYXJ0IG9mIHRoZSBvcmlnaW5hbCBzaWduYWwuIFRoZSBwYXJ0IG9mIHRoZSByZWZlcmVuY2Ugc2lnbmFsIHRvIGJlIGNvbXBhcmVkIGlzIHRha2VuIGZyb20gdGhlIGJlZ2lubmluZyBhbmQgZW5kaW5nIHNjcnViIHZhbHVlcyBvZiB0aGUgZ2VzdHVyZS4gVGhlIHRpbWluZyBvZiB0aGUgZ2VzdHVyZSBpcyBzY2FsZWQgbGluZWFybHkgdG8gbWF0Y2ggdGhlIHRpbWluZyBvZiB0aGUgcmVmZXJlbmNlLgoKRm9yIHZvY2FsIGNvbXBhcmlzb25zLCB0aGUgcGFydCBvZiB0aGUgcmVjb3JkaW5nIGNvbnRhaW5pbmcgdGhlIHV0dGVyYW5jZSBpcyBsYWJlbGVkIGZvciBib3RoIHRoZSByZWZlcmVuY2UgYW5kIHN1YmplY3QgcmVjb3JkaW5ncy4gVGhlIHRpbWluZyBvZiB0aGUgdm9jYWwgcmVjb3JkaW5nIGlzIHNjYWxlZCBsaW5lYXJseSB0byBtYXRjaCB0aGUgcmVmZXJlbmNlLiBObyB0aW1lIHdhcnBpbmcgd2FzIGRvbmUgaW4gb3JkZXIgdG8gcHJlc2VydmUgdGhlIG9yaWdpbmFsIHJoeXRobSBvZiB0aGUgcmVjb3JkaW5nLiAgCgoKYGBge3J9CiMgRm9yIGdlc3R1cmUgZGF0YSwgb25seSBrZWVwIHRoZSBwcm9zb2dyYW0gY29tcGFyaXNvbnMgYnV0IGNhbGwgdGhlbSB0aGUgc2FtZSB0aGluZyBhcyB0aGUgY29ycmVzcG9uZGluZyBjb21wYXJpc29ucyBmb3Igdm9pY2UKZ2VzdF9kYXRhMiA8LSBhbGxfZGF0YSAlPiUgZmlsdGVyKHR5cGU9PSdnZXN0dXJlJykgJT4lIG11dGF0ZShjb3JyX25vdGltaW5nID0gY29ycl9wc2dfbm90aW1pbmcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJtc2Vfbm90aW1pbmcgPSBybXNlX3BzZ19ub3RpbWluZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JyID0gY29ycl9wc2csIHJtc2U9IHJtc2VfcHNnKSAKbG9uZ19kYXRhIDwtIGFsbF9kYXRhICU+JSBmaWx0ZXIodHlwZT09ICd2b2ljZScpICU+JSBiaW5kX3Jvd3MoZ2VzdF9kYXRhMikgJT4lIAogICAgICAgICAgICAgIyBHZXQgcmlkIG9mIGNvbHVtbnMgY29udGFpbmluZyB0aGUgcHJvc29ncmFtIGNvbXBhcmlzb25zCiAgICAgICAgICAgICBtdXRhdGUoY29ycl9wc2cgPSBOVUxMLCBybXNlX3BzZyA9IE5VTEwsIGNvcnJfcHNnX25vdGltaW5nID0gTlVMTCwgcm1zZV9wc2dfbm90aW1pbmcgPSBOVUxMKSAlPiUKICAgICAgICAgICAgICMgTWFrZSBsb25nIHZlcnNpb24gb2YgZGF0YQogICAgICAgICAgICAgcGl2b3RfbG9uZ2VyKGMoJ2NvcnInLCAnY29ycl9ub3RpbWluZycsICdybXNlJywgJ3Jtc2Vfbm90aW1pbmcnKSwgbmFtZXNfdG8gPSAibWV0cmljcyIsIHZhbHVlc190byA9ICJzY29yZSIpCmBgYAoKIyMgT3ZlcmFsbAoKSW50ZXJlc3RpbmcsIHRoZSBibGluZCBjaGlyb25vbXkgbWVkaWFuIHNjb3JlcyBkb24ndCBjaGFuZ2UgbXVjaCBiZWNhdXNlIHRoZXkgYXJlIGFscmVhZHkgbm90IHNvIGdyZWF0LiBUaGUgc2NvcmVzIGZvciB0aGUgb3RoZXIgY29uZGl0aW9ucyBhcmUgd29yc2UuIEludGVyZXN0aW5nbHksIGd1aWRlZCBjaGlyb25vbXkgcGVyZm9ybXMgdGhlIGJlc3Qgd2hlbiB0aW1pbmcgaXMgdGFrZW4gaW50byBhY2NvdW50LiBFdmVuIHRob3VnaCBpdHMgc2NvcmVzIGFyZSBzbGlnaHRseSB3b3JzZSB0aGFuIHdoZW4gdGltaW5nIGlzIG5vdCB0YWtlbiBpbnRvIGFjY291bnQsIGl0IHN0aWxsIG1hbmFnZXMgdG8gaGF2ZSAiZ29vZCIgc2NvcmVzIChpbiBjb21wYXJpc29uIHdpdGggcmVzdWx0cyBmcm9tIGQnQWxlc3NhbmRybyAyMDExKSAtLSBhIG1lZGlhbiBjb3JyZWxhdGlvbiBvZiA+MC44IGFuZCBtZWRpYW4gUk1TRSBhcm91bmQgMlNULiAKCkZvciByZWFkaW5nLCBpdCBpcyBub3JtYWwgdGhhdCB0aGVyZSB3b3VsZCBiZSBtb3JlIHZhcmlhdGlvbiBpbiB0aW1pbmcuIAoKYGBge3J9CmxvbmdfZGF0YSAlPiUgZmlsdGVyKG1ldHJpY3M9PSAnY29ycl9ub3RpbWluZycgfCBtZXRyaWNzID09ICdjb3JyJykgJT4lCiAgICAgICAgICAgICAgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbiwgeT1zY29yZSkpICsKICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBtZXRyaWNzKSkgKwogICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKC0wLjgsIDEsIGJ5PTAuMikpICsKICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIkNvbXBhcmlzb24gdHlwZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2l0aCB0aW1pbmciLCAiTm8gdGltaW5nIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9d2VzX3BhbGV0dGUoIk1vb25yaXNlMyIpKSArCiAgICAgICAgICAgICAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24sIHRpbWluZyB2cyBuby10aW1pbmciKQoKYGBgCgpgYGB7cn0KbG9uZ19kYXRhICU+JSBmaWx0ZXIobWV0cmljcz09ICdybXNlX25vdGltaW5nJyB8IG1ldHJpY3MgPT0gJ3Jtc2UnKSAlPiUKICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9Y29uZGl0aW9uLCB5PXNjb3JlKSkgKwogICAgICAgICAgICAgIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IG1ldHJpY3MpKSArCiAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgOCwgYnk9MSkpICsgCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXaXRoIHRpbWluZyIsICJObyB0aW1pbmciKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJNb29ucmlzZTIiKSkgKwogICAgICAgICAgICAgIGxhYnModGl0bGU9IlJNU0UsIHRpbWluZyB2cyBuby10aW1pbmciKQpgYGAKCiMjIExlYXJuZXJzIHZzIE5hdGl2ZXMKCk5vdCBzbyBtdWNoIGRpZmZlcmVuY2UgYmV0d2VlbiBuYXRpdmVzIGFuZCBub24tbmF0aXZlcyB3aGVuIHRpbWluZyBpcyB0YWtlbiBpbnRvIGFjY291bnQuCgpgYGB7cn0KbCA8LSBsb25nX2RhdGEgJT4lIGZpbHRlcihtZXRyaWNzPT0gJ2NvcnJfbm90aW1pbmcnIHwgbWV0cmljcyA9PSAnY29ycicpICU+JQogICAgICAgICAgICAgIGZpbHRlcihzdWJqZWN0ICVpbiUgbGVhcm5lcnMkaWQpICU+JQogICAgICAgICAgICAgIGdncGxvdChhZXMoeD1jb25kaXRpb24sIHk9c2NvcmUpKSArCiAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gbWV0cmljcykpICsKICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMC44LCAxLCBieT0uMikpICsgCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldpdGggdGltaW5nIiwgIk5vIHRpbWluZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJNb29ucmlzZTMiKSkgKwogICAgICAgICAgICAgIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uLCB0aW1pbmcgdnMgbm8tdGltaW5nIiwgc3VidGl0bGU9IkxlYXJuZXJzIikKCm4gPC0gbG9uZ19kYXRhICU+JSBmaWx0ZXIobWV0cmljcz09ICdjb3JyX25vdGltaW5nJyB8IG1ldHJpY3MgPT0gJ2NvcnInKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoc3ViamVjdCAlaW4lIG5hdGl2ZXMkaWQpICU+JQogICAgICAgICAgICAgIGdncGxvdChhZXMoeD1jb25kaXRpb24sIHk9c2NvcmUpKSArCiAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gbWV0cmljcykpICsKICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMC44LCAxLCBieT0uMikpICsgCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldpdGggdGltaW5nIiwgIk5vIHRpbWluZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJNb29ucmlzZTMiKSkgKwogICAgICAgICAgICAgIGxhYnMoc3VidGl0bGU9Ik5hdGl2ZXMiKQoKZ3JpZC5hcnJhbmdlKGwsIG4sIG5jb2w9MSkKCmBgYApgYGB7cn0KbCA8LSBsb25nX2RhdGEgJT4lIGZpbHRlcihtZXRyaWNzPT0gJ3Jtc2Vfbm90aW1pbmcnIHwgbWV0cmljcyA9PSAncm1zZScpICU+JQogICAgICAgICAgICAgIGZpbHRlcihzdWJqZWN0ICVpbiUgbGVhcm5lcnMkaWQpICU+JQogICAgICAgICAgICAgIGdncGxvdChhZXMoeD1jb25kaXRpb24sIHk9c2NvcmUpKSArCiAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgOCwgYnk9MSkpICsgCiAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gbWV0cmljcykpICsKICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIkNvbXBhcmlzb24gdHlwZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2l0aCB0aW1pbmciLCAiTm8gdGltaW5nIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9d2VzX3BhbGV0dGUoIk1vb25yaXNlMiIpKSArCiAgICAgICAgICAgICAgbGFicyh0aXRsZT0iUk1TRSwgdGltaW5nIHZzIG5vLXRpbWluZyIsIHN1YnRpdGxlPSJMZWFybmVycyIpCgpuIDwtIGxvbmdfZGF0YSAlPiUgZmlsdGVyKG1ldHJpY3M9PSAncm1zZV9ub3RpbWluZycgfCBtZXRyaWNzID09ICdybXNlJykgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKHN1YmplY3QgJWluJSBuYXRpdmVzJGlkKSAlPiUKICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9Y29uZGl0aW9uLCB5PXNjb3JlKSkgKwogICAgICAgICAgICAgIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IG1ldHJpY3MpKSArCiAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgOCwgYnk9MSkpICsgCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldpdGggdGltaW5nIiwgIk5vIHRpbWluZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJNb29ucmlzZTIiKSkgKwogICAgICAgICAgICAgIGxhYnMoc3VidGl0bGU9Ik5hdGl2ZXMiKQoKZ3JpZC5hcnJhbmdlKGwsIG4sIG5jb2w9MSkKCmBgYAoKIyMgTXVzaWNpYW5zIHZzIE5vbi1tdXNpY2lhbnMKCk5vdCBiaWcgZGlmZmVyZW5jZSBiZXR3ZWVuIG11c2ljaWFucyBhbmQgbm9uLW11c2ljaWFucyBlaXRoZXIgd2hlbiB0aW1pbmcgaXMgdGFrZW4gaW50byBhY2NvdW50LgoKYGBge3J9Cm0gPC0gbG9uZ19kYXRhICU+JSBmaWx0ZXIobWV0cmljcz09ICdjb3JyX25vdGltaW5nJyB8IG1ldHJpY3MgPT0gJ2NvcnInKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoc3ViamVjdCAlaW4lIG11c2ljaWFucyRpZCkgJT4lCiAgICAgICAgICAgICAgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbiwgeT1zY29yZSkpICsKICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBtZXRyaWNzKSkgKwogICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKC0wLjgsIDEsIGJ5PS4yKSkgKyAKICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIkNvbXBhcmlzb24gdHlwZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2l0aCB0aW1pbmciLCAiTm8gdGltaW5nIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9d2VzX3BhbGV0dGUoIk1vb25yaXNlMyIpKSArCiAgICAgICAgICAgICAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24sIHRpbWluZyB2cyBuby10aW1pbmciLCBzdWJ0aXRsZT0iTXVzaWNpYW5zIikKCm5tIDwtIGxvbmdfZGF0YSAlPiUgZmlsdGVyKG1ldHJpY3M9PSAnY29ycl9ub3RpbWluZycgfCBtZXRyaWNzID09ICdjb3JyJykgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKHN1YmplY3QgJWluJSBub25tdXMkaWQpICU+JQogICAgICAgICAgICAgIGdncGxvdChhZXMoeD1jb25kaXRpb24sIHk9c2NvcmUpKSArCiAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoLTAuOCwgMSwgYnk9LjIpKSArIAogICAgICAgICAgICAgIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IG1ldHJpY3MpKSArCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldpdGggdGltaW5nIiwgIk5vIHRpbWluZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJNb29ucmlzZTMiKSkgKwogICAgICAgICAgICAgIGxhYnMoc3VidGl0bGU9Ik5vbi1tdXNpY2lhbnMiKQoKZ3JpZC5hcnJhbmdlKG0sIG5tLCBuY29sPTEpCmBgYAoKYGBge3J9Cm0gPC0gbG9uZ19kYXRhICU+JSBmaWx0ZXIobWV0cmljcz09ICdybXNlX25vdGltaW5nJyB8IG1ldHJpY3MgPT0gJ3Jtc2UnKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoc3ViamVjdCAlaW4lIG11c2ljaWFucyRpZCkgJT4lCiAgICAgICAgICAgICAgZ2dwbG90KGFlcyh4PWNvbmRpdGlvbiwgeT1zY29yZSkpICsKICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBtZXRyaWNzKSkgKwogICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsIDgsIGJ5PTEpKSArIAogICAgICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiQ29tcGFyaXNvbiB0eXBlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXaXRoIHRpbWluZyIsICJObyB0aW1pbmciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcz13ZXNfcGFsZXR0ZSgiTW9vbnJpc2UyIikpICsKICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJSTVNFLCB0aW1pbmcgdnMgbm8tdGltaW5nIiwgc3VidGl0bGU9IkxlYXJuZXJzIikKCm5tIDwtIGxvbmdfZGF0YSAlPiUgZmlsdGVyKG1ldHJpY3M9PSAncm1zZV9ub3RpbWluZycgfCBtZXRyaWNzID09ICdybXNlJykgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKHN1YmplY3QgJWluJSBub25tdXMkaWQpICU+JQogICAgICAgICAgICAgIGdncGxvdChhZXMoeD1jb25kaXRpb24sIHk9c2NvcmUpKSArCiAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gbWV0cmljcykpICsKICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLCA4LCBieT0xKSkgKyAKICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIkNvbXBhcmlzb24gdHlwZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2l0aCB0aW1pbmciLCAiTm8gdGltaW5nIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9d2VzX3BhbGV0dGUoIk1vb25yaXNlMiIpKSArCiAgICAgICAgICAgICAgbGFicyhzdWJ0aXRsZT0iTmF0aXZlcyIpCgpncmlkLmFycmFuZ2UobSwgbm0sIG5jb2w9MSkKCmBgYAoKIyMgQnkgUGhyYXNlCgpCeSBjb21wYXJpaW5nIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gZ3VpZGVkIGNoaXJvbm9teSB3aXRoIGFuZCB3aXRob3V0IHRpbWluZyB0YWtlbiBpbnRvIGFjY291bnQsIHdlIGNhbiBzZWUgdGhhdCBzb21lIHBocmFzZXMgd2VyZSB0cmlja2llciB0byBjb250cm9sIHRoZSB0aW1pbmcgb2YgdGhhbiBvdGhlcnMgKGUuZy4gN2JpcywgMTAsIDIxLCAyMWJpcykKCkknbSBub3Qgc3VyZSBob3cgbWVhbmluZ2Z1bCBpdCBpcyB0byBjb21wYXJlIHRoZSB2b2NhbCBwcm9udW5jaWF0aW9ucyB3aXRoIHdpdGhvdXQgZHluYW1pYyB0aW1lIHdhcnBpbmcgYmVjYXVzZSB0aGVyZSBpcyBuYXR1cmFsIHZhcmlhdGlvbiBpbiB0aGUgdm9pY2UuIAoKYGBge3J9CmNpIDwtIGxvbmdfZGF0YSAlPiUgZmlsdGVyKG1ldHJpY3M9PSAnY29ycl9ub3RpbWluZycgfCBtZXRyaWNzID09ICdjb3JyJykgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKGNvbmRpdGlvbj09J2d1aWRlJykgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKHBpZCA9IGZjdF9yZWxldmVsKHBpZCwgIjIiLCAiMmJpcyIsICI3IiwgIjdiaXMiLCAiOCIsICI4YmlzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwIiwgIjEwYmlzIiwgIjExIiwgIjExYmlzIiwgIjIxIiwgIjIxYmlzIikpICU+JQogICAgICAgICAgICAgIGdncGxvdChhZXMoeD1waWQsIHk9c2NvcmUpKSArCiAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gbWV0cmljcykpICsKICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMC44LCAxLCBieT0uMikpICsgCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldpdGggdGltaW5nIiwgIk5vIHRpbWluZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJNb29ucmlzZTMiKSkgKwogICAgICAgICAgICAgIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uLCB0aW1pbmcgdnMgbm8tdGltaW5nIiwgc3VidGl0bGU9Ikd1aWRlZCBDaGlyb25vbXkiKQoKdmkgPC0gbG9uZ19kYXRhICU+JSBmaWx0ZXIobWV0cmljcz09ICdjb3JyX25vdGltaW5nJyB8IG1ldHJpY3MgPT0gJ2NvcnInKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoY29uZGl0aW9uPT0naW1pdGF0aW9uJykgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKHBpZCA9IGZjdF9yZWxldmVsKHBpZCwgIjIiLCAiMmJpcyIsICI3IiwgIjdiaXMiLCAiOCIsICI4YmlzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwIiwgIjEwYmlzIiwgIjExIiwgIjExYmlzIiwgIjIxIiwgIjIxYmlzIikpICU+JQogICAgICAgICAgICAgIGdncGxvdChhZXMoeD1waWQsIHk9c2NvcmUpKSArCiAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gbWV0cmljcykpICsKICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMC44LCAxLCBieT0uMikpICsgCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldpdGggdGltaW5nIiwgIk5vIHRpbWluZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJNb29ucmlzZTMiKSkgKwogICAgICAgICAgICAgIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uLCB0aW1pbmcgdnMgbm8tdGltaW5nIiwgc3VidGl0bGU9IlZvY2FsIENvbXBhcmlzb24iKQoKZ3JpZC5hcnJhbmdlKGNpLCB2aSwgbmNvbD0xKQpgYGAKCmBgYHtyfQpjaSA8LSBsb25nX2RhdGEgJT4lIGZpbHRlcihtZXRyaWNzPT0gJ3Jtc2Vfbm90aW1pbmcnIHwgbWV0cmljcyA9PSAncm1zZScpICU+JQogICAgICAgICAgICAgIGZpbHRlcihjb25kaXRpb249PSdndWlkZScpICU+JQogICAgICAgICAgICAgIG11dGF0ZShwaWQgPSBmY3RfcmVsZXZlbChwaWQsICIyIiwgIjJiaXMiLCAiNyIsICI3YmlzIiwgIjgiLCAiOGJpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMCIsICIxMGJpcyIsICIxMSIsICIxMWJpcyIsICIyMSIsICIyMWJpcyIpKSAlPiUKICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9cGlkLCB5PXNjb3JlKSkgKwogICAgICAgICAgICAgIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IG1ldHJpY3MpKSArCiAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgOCwgYnk9MSkpICsgCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldpdGggdGltaW5nIiwgIk5vIHRpbWluZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJSb3lhbDIiKSkgKwogICAgICAgICAgICAgIGxhYnModGl0bGU9IlJNU0UsIHRpbWluZyB2cyBuby10aW1pbmciLCBzdWJ0aXRsZT0iR3VpZGVkIENoaXJvbm9teSIpCgp2aSA8LSBsb25nX2RhdGEgJT4lIGZpbHRlcihtZXRyaWNzPT0gJ3Jtc2Vfbm90aW1pbmcnIHwgbWV0cmljcyA9PSAncm1zZScpICU+JQogICAgICAgICAgICAgIGZpbHRlcihjb25kaXRpb249PSdpbWl0YXRpb24nKSAlPiUKICAgICAgICAgICAgICBtdXRhdGUocGlkID0gZmN0X3JlbGV2ZWwocGlkLCAiMiIsICIyYmlzIiwgIjciLCAiN2JpcyIsICI4IiwgIjhiaXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAiLCAiMTBiaXMiLCAiMTEiLCAiMTFiaXMiLCAiMjEiLCAiMjFiaXMiKSkgJT4lCiAgICAgICAgICAgICAgZ2dwbG90KGFlcyh4PXBpZCwgeT1zY29yZSkpICsKICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBtZXRyaWNzKSkgKwogICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsIDgsIGJ5PTEpKSArIAogICAgICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiQ29tcGFyaXNvbiB0eXBlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXaXRoIHRpbWluZyIsICJObyB0aW1pbmciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcz13ZXNfcGFsZXR0ZSgiUm95YWwyIikpICsKICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJSTVNFLCB0aW1pbmcgdnMgbm8tdGltaW5nIiwgc3VidGl0bGU9IlZvY2FsIENvbXBhcmlzb24iKQoKZ3JpZC5hcnJhbmdlKGNpLCB2aSwgbmNvbD0xKQpgYGAKCiMjIEJ5IFBocmFzZSBhbmQgc3ViamVjdCBncm91cHMKCiMjIyBGb3IgZ3VpZGVkIGNoaXJvbm9teQpTZWVtcyB0byBiZSBhbiBlcXVhbGl6ZXIgYmV0d2VlbiBuYXRpdmVzIGFuZCBub24tbmF0aXZlcy4gTm90IGh1Z2UgYW1vdW50IG9mIGRpZmZlcmVuY2UuCgpgYGB7cn0KbGcgPC0gbG9uZ19kYXRhICU+JSBmaWx0ZXIobWV0cmljcz09ICdjb3JyX25vdGltaW5nJyB8IG1ldHJpY3MgPT0gJ2NvcnInKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoc3ViamVjdCAlaW4lIGxlYXJuZXJzJGlkKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoY29uZGl0aW9uPT0nZ3VpZGUnKSAlPiUKICAgICAgICAgICAgICBtdXRhdGUocGlkID0gZmN0X3JlbGV2ZWwocGlkLCAiMiIsICIyYmlzIiwgIjciLCAiN2JpcyIsICI4IiwgIjhiaXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAiLCAiMTBiaXMiLCAiMTEiLCAiMTFiaXMiLCAiMjEiLCAiMjFiaXMiKSkgJT4lCiAgICAgICAgICAgICAgZ2dwbG90KGFlcyh4PXBpZCwgeT1zY29yZSkpICsKICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBtZXRyaWNzKSkgKwogICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKC0wLjgsIDEsIGJ5PS4yKSkgKyAKICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIkNvbXBhcmlzb24gdHlwZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2l0aCB0aW1pbmciLCAiTm8gdGltaW5nIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9d2VzX3BhbGV0dGUoIk1vb25yaXNlMyIpKSArCiAgICAgICAgICAgICAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24sIHRpbWluZyB2cyBuby10aW1pbmciLCBzdWJ0aXRsZT0iR3VpZGVkIENoaXJvbm9teSwgTGVhcm5lcnMiKQoKbmcgPC0gbG9uZ19kYXRhICU+JSBmaWx0ZXIobWV0cmljcz09ICdjb3JyX25vdGltaW5nJyB8IG1ldHJpY3MgPT0gJ2NvcnInKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoc3ViamVjdCAlaW4lIG5hdGl2ZXMkaWQpICU+JQogICAgICAgICAgICAgIGZpbHRlcihjb25kaXRpb249PSdndWlkZScpICU+JQogICAgICAgICAgICAgIG11dGF0ZShwaWQgPSBmY3RfcmVsZXZlbChwaWQsICIyIiwgIjJiaXMiLCAiNyIsICI3YmlzIiwgIjgiLCAiOGJpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMCIsICIxMGJpcyIsICIxMSIsICIxMWJpcyIsICIyMSIsICIyMWJpcyIpKSAlPiUKICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9cGlkLCB5PXNjb3JlKSkgKwogICAgICAgICAgICAgIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IG1ldHJpY3MpKSArCiAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoLTAuOCwgMSwgYnk9LjIpKSArIAogICAgICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiQ29tcGFyaXNvbiB0eXBlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXaXRoIHRpbWluZyIsICJObyB0aW1pbmciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcz13ZXNfcGFsZXR0ZSgiTW9vbnJpc2UzIikpICsKICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiwgdGltaW5nIHZzIG5vLXRpbWluZyIsIHN1YnRpdGxlPSJHdWlkZWQgQ2hpcm9ub215LCBOYXRpdmVzIikKCmdyaWQuYXJyYW5nZShsZywgbmcsIG5jb2w9MSkKYGBgCgojIyMgRm9yIGJsaW5kIGNoaXJvbm9teToKCkEgY291cGxlIG9mIHBocmFzZXMgbmF0aXZlcyBoYWQgbW9yZSB0cm91YmxlIHdpdGguIENvdWxkIGJlIHRoYXQgdGhleSBhcmUgbGVzcyBjb25zY2lvdXMgb2YgdGhlIGZyZXF1ZW5jeSBjdXJ2ZT8KCmBgYHtyfQpsYiA8LSBsb25nX2RhdGEgJT4lIGZpbHRlcihtZXRyaWNzPT0gJ2NvcnJfbm90aW1pbmcnIHwgbWV0cmljcyA9PSAnY29ycicpICU+JQogICAgICAgICAgICAgIGZpbHRlcihzdWJqZWN0ICVpbiUgbGVhcm5lcnMkaWQpICU+JQogICAgICAgICAgICAgIGZpbHRlcihjb25kaXRpb249PSdibGluZCcpICU+JQogICAgICAgICAgICAgIG11dGF0ZShwaWQgPSBmY3RfcmVsZXZlbChwaWQsICIyIiwgIjJiaXMiLCAiNyIsICI3YmlzIiwgIjgiLCAiOGJpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMCIsICIxMGJpcyIsICIxMSIsICIxMWJpcyIsICIyMSIsICIyMWJpcyIpKSAlPiUKICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9cGlkLCB5PXNjb3JlKSkgKwogICAgICAgICAgICAgIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IG1ldHJpY3MpKSArCiAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoLTAuOCwgMSwgYnk9LjIpKSArIAogICAgICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiQ29tcGFyaXNvbiB0eXBlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXaXRoIHRpbWluZyIsICJObyB0aW1pbmciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcz13ZXNfcGFsZXR0ZSgiTW9vbnJpc2UzIikpICsKICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiwgdGltaW5nIHZzIG5vLXRpbWluZyIsIHN1YnRpdGxlPSJCbGluZCBDaGlyb25vbXksIExlYXJuZXJzIikKCm5iIDwtIGxvbmdfZGF0YSAlPiUgZmlsdGVyKG1ldHJpY3M9PSAnY29ycl9ub3RpbWluZycgfCBtZXRyaWNzID09ICdjb3JyJykgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKHN1YmplY3QgJWluJSBuYXRpdmVzJGlkKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoY29uZGl0aW9uPT0nYmxpbmQnKSAlPiUKICAgICAgICAgICAgICBtdXRhdGUocGlkID0gZmN0X3JlbGV2ZWwocGlkLCAiMiIsICIyYmlzIiwgIjciLCAiN2JpcyIsICI4IiwgIjhiaXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAiLCAiMTBiaXMiLCAiMTEiLCAiMTFiaXMiLCAiMjEiLCAiMjFiaXMiKSkgJT4lCiAgICAgICAgICAgICAgZ2dwbG90KGFlcyh4PXBpZCwgeT1zY29yZSkpICsKICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBtZXRyaWNzKSkgKwogICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKC0wLjgsIDEsIGJ5PS4yKSkgKyAKICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIkNvbXBhcmlzb24gdHlwZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2l0aCB0aW1pbmciLCAiTm8gdGltaW5nIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9d2VzX3BhbGV0dGUoIk1vb25yaXNlMyIpKSArCiAgICAgICAgICAgICAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24sIHRpbWluZyB2cyBuby10aW1pbmciLCBzdWJ0aXRsZT0iQmxpbmQgQ2hpcm9ub215LCBOYXRpdmVzIikKCmdyaWQuYXJyYW5nZShsYiwgbmIsIG5jb2w9MSkKYGBgCgojIyMgVm9jYWwgSW1pdGF0aW9uCgpOb3QgdG9vIG11Y2ggZGlmZmVyZW5jZS4gTmF0aXZlcyBoYXZlIG1vcmUgdmFyaWF0aW9uLgoKYGBge3J9CmxpIDwtIGxvbmdfZGF0YSAlPiUgZmlsdGVyKG1ldHJpY3M9PSAnY29ycl9ub3RpbWluZycgfCBtZXRyaWNzID09ICdjb3JyJykgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKHN1YmplY3QgJWluJSBsZWFybmVycyRpZCkgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKGNvbmRpdGlvbj09J2ltaXRhdGlvbicpICU+JQogICAgICAgICAgICAgIG11dGF0ZShwaWQgPSBmY3RfcmVsZXZlbChwaWQsICIyIiwgIjJiaXMiLCAiNyIsICI3YmlzIiwgIjgiLCAiOGJpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMCIsICIxMGJpcyIsICIxMSIsICIxMWJpcyIsICIyMSIsICIyMWJpcyIpKSAlPiUKICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9cGlkLCB5PXNjb3JlKSkgKwogICAgICAgICAgICAgIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IG1ldHJpY3MpKSArCiAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoLTAuOCwgMSwgYnk9LjIpKSArIAogICAgICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiQ29tcGFyaXNvbiB0eXBlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXaXRoIHRpbWluZyIsICJObyB0aW1pbmciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcz13ZXNfcGFsZXR0ZSgiTW9vbnJpc2UzIikpICsKICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiwgdGltaW5nIHZzIG5vLXRpbWluZyIsIHN1YnRpdGxlPSJJbWl0YXRpb24sIExlYXJuZXJzIikKCm5pIDwtIGxvbmdfZGF0YSAlPiUgZmlsdGVyKG1ldHJpY3M9PSAnY29ycl9ub3RpbWluZycgfCBtZXRyaWNzID09ICdjb3JyJykgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKHN1YmplY3QgJWluJSBuYXRpdmVzJGlkKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoY29uZGl0aW9uPT0naW1pdGF0aW9uJykgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKHBpZCA9IGZjdF9yZWxldmVsKHBpZCwgIjIiLCAiMmJpcyIsICI3IiwgIjdiaXMiLCAiOCIsICI4YmlzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwIiwgIjEwYmlzIiwgIjExIiwgIjExYmlzIiwgIjIxIiwgIjIxYmlzIikpICU+JQogICAgICAgICAgICAgIGdncGxvdChhZXMoeD1waWQsIHk9c2NvcmUpKSArCiAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gbWV0cmljcykpICsKICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMC44LCAxLCBieT0uMikpICsgCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldpdGggdGltaW5nIiwgIk5vIHRpbWluZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJNb29ucmlzZTMiKSkgKwogICAgICAgICAgICAgIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uLCB0aW1pbmcgdnMgbm8tdGltaW5nIiwgc3VidGl0bGU9IkltaXRhdGlvbiwgTmF0aXZlcyIpCgpncmlkLmFycmFuZ2UobGksIG5pLCBuY29sPTEpCmBgYAoKIyMjIFZvY2FsIFJlYWRpbmlnCgpOb3QgdG9vIG11Y2ggZGlmZmVyZW5jZS4gTmF0aXZlcyBoYXZlIG1vcmUgdmFyaWF0aW9uLiBOb24tbmF0aXZlcyBzZWVtZWQgdG8gaGF2ZSBpc3N1ZXMgd2l0aCAxMCwgMTBiaXMsIDIxLgoKYGBge3J9CgpsaSA8LSBsb25nX2RhdGEgJT4lIGZpbHRlcihtZXRyaWNzPT0gJ2NvcnJfbm90aW1pbmcnIHwgbWV0cmljcyA9PSAnY29ycicpICU+JQogICAgICAgICAgICAgIGZpbHRlcihzdWJqZWN0ICVpbiUgbGVhcm5lcnMkaWQpICU+JQogICAgICAgICAgICAgIGZpbHRlcihjb25kaXRpb249PSdsZWN0dXJlJykgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKHBpZCA9IGZjdF9yZWxldmVsKHBpZCwgIjIiLCAiMmJpcyIsICI3IiwgIjdiaXMiLCAiOCIsICI4YmlzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwIiwgIjEwYmlzIiwgIjExIiwgIjExYmlzIiwgIjIxIiwgIjIxYmlzIikpICU+JQogICAgICAgICAgICAgIGdncGxvdChhZXMoeD1waWQsIHk9c2NvcmUpKSArCiAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gbWV0cmljcykpICsKICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMC44LCAxLCBieT0uMikpICsgCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldpdGggdGltaW5nIiwgIk5vIHRpbWluZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJNb29ucmlzZTMiKSkgKwogICAgICAgICAgICAgIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uLCB0aW1pbmcgdnMgbm8tdGltaW5nIiwgc3VidGl0bGU9IkxlY3R1cmUsIExlYXJuZXJzIikKCm5pIDwtIGxvbmdfZGF0YSAlPiUgZmlsdGVyKG1ldHJpY3M9PSAnY29ycl9ub3RpbWluZycgfCBtZXRyaWNzID09ICdjb3JyJykgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKHN1YmplY3QgJWluJSBuYXRpdmVzJGlkKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoY29uZGl0aW9uPT0nbGVjdHVyZScpICU+JQogICAgICAgICAgICAgIG11dGF0ZShwaWQgPSBmY3RfcmVsZXZlbChwaWQsICIyIiwgIjJiaXMiLCAiNyIsICI3YmlzIiwgIjgiLCAiOGJpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMCIsICIxMGJpcyIsICIxMSIsICIxMWJpcyIsICIyMSIsICIyMWJpcyIpKSAlPiUKICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9cGlkLCB5PXNjb3JlKSkgKwogICAgICAgICAgICAgIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IG1ldHJpY3MpKSArCiAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoLTAuOCwgMSwgYnk9LjIpKSArIAogICAgICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiQ29tcGFyaXNvbiB0eXBlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXaXRoIHRpbWluZyIsICJObyB0aW1pbmciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcz13ZXNfcGFsZXR0ZSgiTW9vbnJpc2UzIikpICsKICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiwgdGltaW5nIHZzIG5vLXRpbWluZyIsIHN1YnRpdGxlPSJMZWN0dXJlLCBOYXRpdmVzIikKCmdyaWQuYXJyYW5nZShsaSwgbmksIG5jb2w9MSkKYGBgCgojIyMgR3VpZGVkIENoaXJvbm9teSAtIG11c2ljaWFucyB2cyBub24tbXVzaWNpYW5zCgpNdXNpY2lhbnMgZG9uJ3QgZG8gYmV0dGVyIGZvciBndWlkZWQgY2hpcm9ub215CgpgYGB7cn0KbWcgPC0gbG9uZ19kYXRhICU+JSBmaWx0ZXIobWV0cmljcz09ICdjb3JyX25vdGltaW5nJyB8IG1ldHJpY3MgPT0gJ2NvcnInKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoc3ViamVjdCAlaW4lIG11c2ljaWFucyRpZCkgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKGNvbmRpdGlvbj09J2d1aWRlJykgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKHBpZCA9IGZjdF9yZWxldmVsKHBpZCwgIjIiLCAiMmJpcyIsICI3IiwgIjdiaXMiLCAiOCIsICI4YmlzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwIiwgIjEwYmlzIiwgIjExIiwgIjExYmlzIiwgIjIxIiwgIjIxYmlzIikpICU+JQogICAgICAgICAgICAgIGdncGxvdChhZXMoeD1waWQsIHk9c2NvcmUpKSArCiAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gbWV0cmljcykpICsKICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMC44LCAxLCBieT0uMikpICsgCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldpdGggdGltaW5nIiwgIk5vIHRpbWluZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJNb29ucmlzZTMiKSkgKwogICAgICAgICAgICAgIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uLCB0aW1pbmcgdnMgbm8tdGltaW5nIiwgc3VidGl0bGU9Ikd1aWRlZCBDaGlyb25vbXksIE11c2ljaWFucyIpCgpuZyA8LSBsb25nX2RhdGEgJT4lIGZpbHRlcihtZXRyaWNzPT0gJ2NvcnJfbm90aW1pbmcnIHwgbWV0cmljcyA9PSAnY29ycicpICU+JQogICAgICAgICAgICAgIGZpbHRlcihzdWJqZWN0ICVpbiUgbm9ubXVzJGlkKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoY29uZGl0aW9uPT0nZ3VpZGUnKSAlPiUKICAgICAgICAgICAgICBtdXRhdGUocGlkID0gZmN0X3JlbGV2ZWwocGlkLCAiMiIsICIyYmlzIiwgIjciLCAiN2JpcyIsICI4IiwgIjhiaXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAiLCAiMTBiaXMiLCAiMTEiLCAiMTFiaXMiLCAiMjEiLCAiMjFiaXMiKSkgJT4lCiAgICAgICAgICAgICAgZ2dwbG90KGFlcyh4PXBpZCwgeT1zY29yZSkpICsKICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBtZXRyaWNzKSkgKwogICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKC0wLjgsIDEsIGJ5PS4yKSkgKyAKICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIkNvbXBhcmlzb24gdHlwZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2l0aCB0aW1pbmciLCAiTm8gdGltaW5nIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9d2VzX3BhbGV0dGUoIk1vb25yaXNlMyIpKSArCiAgICAgICAgICAgICAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24sIHRpbWluZyB2cyBuby10aW1pbmciLCBzdWJ0aXRsZT0iR3VpZGVkIENoaXJvbm9teSwgTm9uLW11c2ljaWFucyIpCgpncmlkLmFycmFuZ2UobWcsIG5nLCBuY29sPTEpCmBgYAoKIyMjIEJsaW5kIENoaXJvbm9teSAtIG11c2ljaWFucyB2cyBub24tbXVzaWNpYW5zCgpXZSBkb24ndCBsZWFybiBtdWNoIG5ldyBoZXJlLiBNdXNpY2lhbnMgZG8gYmV0dGVyIGZvciBzb21lIHBocmFzZXMgdGhhbiBvdGhlcnMuCgpgYGB7cn0KbWIgPC0gbG9uZ19kYXRhICU+JSBmaWx0ZXIobWV0cmljcz09ICdjb3JyX25vdGltaW5nJyB8IG1ldHJpY3MgPT0gJ2NvcnInKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoc3ViamVjdCAlaW4lIG11c2ljaWFucyRpZCkgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKGNvbmRpdGlvbj09J2JsaW5kJykgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKHBpZCA9IGZjdF9yZWxldmVsKHBpZCwgIjIiLCAiMmJpcyIsICI3IiwgIjdiaXMiLCAiOCIsICI4YmlzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwIiwgIjEwYmlzIiwgIjExIiwgIjExYmlzIiwgIjIxIiwgIjIxYmlzIikpICU+JQogICAgICAgICAgICAgIGdncGxvdChhZXMoeD1waWQsIHk9c2NvcmUpKSArCiAgICAgICAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gbWV0cmljcykpICsKICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgtMC44LCAxLCBieT0uMikpICsgCiAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJDb21wYXJpc29uIHR5cGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldpdGggdGltaW5nIiwgIk5vIHRpbWluZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPXdlc19wYWxldHRlKCJNb29ucmlzZTMiKSkgKwogICAgICAgICAgICAgIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uLCB0aW1pbmcgdnMgbm8tdGltaW5nIiwgc3VidGl0bGU9IkJsaW5kIENoaXJvbm9teSwgTXVzaWNpYW5zIikKCm5iIDwtIGxvbmdfZGF0YSAlPiUgZmlsdGVyKG1ldHJpY3M9PSAnY29ycl9ub3RpbWluZycgfCBtZXRyaWNzID09ICdjb3JyJykgJT4lCiAgICAgICAgICAgICAgZmlsdGVyKHN1YmplY3QgJWluJSBub25tdXMkaWQpICU+JQogICAgICAgICAgICAgIGZpbHRlcihjb25kaXRpb249PSdibGluZCcpICU+JQogICAgICAgICAgICAgIG11dGF0ZShwaWQgPSBmY3RfcmVsZXZlbChwaWQsICIyIiwgIjJiaXMiLCAiNyIsICI3YmlzIiwgIjgiLCAiOGJpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMCIsICIxMGJpcyIsICIxMSIsICIxMWJpcyIsICIyMSIsICIyMWJpcyIpKSAlPiUKICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9cGlkLCB5PXNjb3JlKSkgKwogICAgICAgICAgICAgIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IG1ldHJpY3MpKSArCiAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoLTAuOCwgMSwgYnk9LjIpKSArIAogICAgICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiQ29tcGFyaXNvbiB0eXBlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXaXRoIHRpbWluZyIsICJObyB0aW1pbmciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcz13ZXNfcGFsZXR0ZSgiTW9vbnJpc2UzIikpICsKICAgICAgICAgICAgICBsYWJzKHRpdGxlPSJDb3JyZWxhdGlvbiwgdGltaW5nIHZzIG5vLXRpbWluZyIsIHN1YnRpdGxlPSJCbGluZCBDaGlyb25vbXksIE5vbi1tdXNpY2lhbnMiKQoKZ3JpZC5hcnJhbmdlKG1iLCBuYiwgbmNvbD0xKQpgYGAK